code-context-control 2.96.0__tar.gz → 2.101.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.96.0/code_context_control.egg-info → code_context_control-2.101.0}/PKG-INFO +1 -1
- {code_context_control-2.96.0 → code_context_control-2.101.0}/cli/c3.py +78 -5
- {code_context_control-2.96.0 → code_context_control-2.101.0}/cli/commands/parser.py +22 -3
- {code_context_control-2.96.0 → code_context_control-2.101.0}/cli/hook_access_guard.py +27 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/cli/hub_server.py +207 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/cli/hub_ui/app.js +3 -1
- code_context_control-2.101.0/cli/hub_ui/components/hub_access.js +353 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/cli/hub_ui/components/topbar.js +1 -1
- {code_context_control-2.96.0 → code_context_control-2.101.0}/cli/server.py +26 -1
- {code_context_control-2.96.0 → code_context_control-2.101.0}/cli/tools/_grants.py +25 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/cli/tools/edit.py +7 -1
- {code_context_control-2.96.0 → code_context_control-2.101.0}/cli/tools/override.py +9 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/cli/tools/read.py +7 -1
- {code_context_control-2.96.0 → code_context_control-2.101.0}/cli/tools/shell.py +25 -1
- {code_context_control-2.96.0 → code_context_control-2.101.0}/cli/tools/status.py +2 -1
- {code_context_control-2.96.0 → code_context_control-2.101.0}/cli/ui/components/access.js +63 -6
- {code_context_control-2.96.0 → code_context_control-2.101.0/code_context_control.egg-info}/PKG-INFO +1 -1
- {code_context_control-2.96.0 → code_context_control-2.101.0}/code_context_control.egg-info/SOURCES.txt +5 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/oracle/services/mobile_api.py +2 -1
- {code_context_control-2.96.0 → code_context_control-2.101.0}/pyproject.toml +1 -1
- {code_context_control-2.96.0 → code_context_control-2.101.0}/services/access_guard.py +386 -95
- {code_context_control-2.96.0 → code_context_control-2.101.0}/services/artifact_store.py +5 -1
- {code_context_control-2.96.0 → code_context_control-2.101.0}/services/claude_md.py +2 -1
- {code_context_control-2.96.0 → code_context_control-2.101.0}/services/override_grants.py +35 -2
- {code_context_control-2.96.0 → code_context_control-2.101.0}/services/override_policy.py +45 -7
- {code_context_control-2.96.0 → code_context_control-2.101.0}/services/override_requests.py +36 -4
- {code_context_control-2.96.0 → code_context_control-2.101.0}/services/subprojects.py +5 -1
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_access_guard_meta.py +40 -0
- code_context_control-2.101.0/tests/test_builtin_modes.py +358 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_c3_shell.py +77 -0
- code_context_control-2.101.0/tests/test_confirm_guard.py +386 -0
- code_context_control-2.101.0/tests/test_hub_override_routes.py +222 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_override_grants.py +11 -2
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_override_requests.py +14 -0
- code_context_control-2.101.0/tests/test_subproject_clear_scope.py +118 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_ui_jsx_syntax.py +49 -3
- {code_context_control-2.96.0 → code_context_control-2.101.0}/LICENSE +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/README.md +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/cli/__init__.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/cli/_hook_utils.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/cli/_shell_writes.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/cli/commands/__init__.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/cli/commands/common.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/cli/docs.html +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/cli/edits.html +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/cli/guide/access.html +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/cli/guide/bitbucket.html +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/cli/guide/credentials.html +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/cli/guide/getting-started.html +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/cli/guide/index.html +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/cli/guide/masking.html +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/cli/guide/oracle.html +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/cli/guide/shared.css +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/cli/guide/tools.html +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/cli/guide/workflow.html +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/cli/hook_artifact.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/cli/hook_auto_snapshot.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/cli/hook_c3_signal.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/cli/hook_c3read.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/cli/hook_dispatch.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/cli/hook_edit_ledger.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/cli/hook_edit_unlock.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/cli/hook_filter.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/cli/hook_ghost_files.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/cli/hook_pretool_enforce.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/cli/hook_prompt_recall.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/cli/hook_read.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/cli/hook_session_stats.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/cli/hook_terse_advisor.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/cli/hub_ui/components/add_project.js +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/cli/hub_ui/components/config_editor.js +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/cli/hub_ui/components/drill_artifacts.js +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/cli/hub_ui/components/drill_health.js +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/cli/hub_ui/components/drill_panel.js +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/cli/hub_ui/components/drill_subprojects.js +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/cli/hub_ui/components/drill_tasks.js +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/cli/hub_ui/components/drill_views.js +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/cli/hub_ui/components/global_search.js +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/cli/hub_ui/components/hub_ci.js +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/cli/hub_ui/components/hub_cred_audit.js +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/cli/hub_ui/components/hub_credentials.js +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/cli/hub_ui/components/hub_enforcement.js +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/cli/hub_ui/components/hub_locks.js +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/cli/hub_ui/components/hub_tokens.js +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/cli/hub_ui/components/mcp_manager.js +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/cli/hub_ui/components/modals.js +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/cli/hub_ui/components/project_card.js +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/cli/hub_ui/components/project_tree.js +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/cli/hub_ui/components/session_drawer.js +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/cli/hub_ui/components/settings_modal.js +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/cli/hub_ui/components/sidebar.js +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/cli/hub_ui/components/summary_bar.js +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/cli/hub_ui/components/task_board.js +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/cli/hub_ui/components/toasts.js +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/cli/hub_ui/state.js +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/cli/hub_ui.html +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/cli/mcp_proxy.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/cli/mcp_server.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/cli/progress.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/cli/tools/__init__.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/cli/tools/_helpers.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/cli/tools/agent.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/cli/tools/artifacts.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/cli/tools/bitbucket.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/cli/tools/ci.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/cli/tools/compress.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/cli/tools/credentials.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/cli/tools/delegate.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/cli/tools/edit_verify.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/cli/tools/edits.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/cli/tools/federate.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/cli/tools/filter.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/cli/tools/impact.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/cli/tools/jira.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/cli/tools/locks.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/cli/tools/memory.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/cli/tools/project.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/cli/tools/search.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/cli/tools/session.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/cli/tools/tasks.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/cli/tools/validate.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/cli/ui/api.js +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/cli/ui/app.js +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/cli/ui/components/bitbucket.js +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/cli/ui/components/chat.js +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/cli/ui/components/credentials.js +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/cli/ui/components/dashboard.js +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/cli/ui/components/edits.js +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/cli/ui/components/enforcement.js +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/cli/ui/components/instructions.js +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/cli/ui/components/jira.js +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/cli/ui/components/memory.js +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/cli/ui/components/sessions.js +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/cli/ui/components/settings.js +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/cli/ui/components/sidebar.js +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/cli/ui/components/tasks.js +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/cli/ui/icons.js +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/cli/ui/pm_shared.js +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/cli/ui/shared.js +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/cli/ui/theme.js +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/cli/ui.html +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/cli/ui_legacy.html +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/cli/ui_nano.html +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/code_context_control.egg-info/dependency_links.txt +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/code_context_control.egg-info/entry_points.txt +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/code_context_control.egg-info/requires.txt +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/code_context_control.egg-info/top_level.txt +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/core/__init__.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/core/config.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/core/ide.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/core/mcp_toml.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/core/web_security.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/oracle/__init__.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/oracle/config.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/oracle/mcp_oracle.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/oracle/oracle_server.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/oracle/oracle_ui.html +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/oracle/services/__init__.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/oracle/services/activity_reporter.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/oracle/services/api_auth.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/oracle/services/c3_bridge.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/oracle/services/chat_engine.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/oracle/services/chat_poll.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/oracle/services/chat_store.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/oracle/services/cross_memory.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/oracle/services/discovery_audit.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/oracle/services/federated_graph.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/oracle/services/health_checker.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/oracle/services/insight_engine.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/oracle/services/local_session.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/oracle/services/memory_reader.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/oracle/services/memory_writer.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/oracle/services/project_scanner.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/oracle/services/review_agent.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/oracle/services/tool_executor.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/oracle/services/tool_registry.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/oracle/ui/activity.js +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/oracle/ui/agents.js +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/oracle/ui/app.js +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/oracle/ui/busy.js +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/oracle/ui/chat/conversations.js +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/oracle/ui/chat/input.js +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/oracle/ui/chat/markdown.js +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/oracle/ui/chat/send.js +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/oracle/ui/chat/stream_renderer.js +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/oracle/ui/chat/toolbar.js +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/oracle/ui/core.js +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/oracle/ui/crossgraph.js +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/oracle/ui/header.js +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/oracle/ui/insights.js +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/oracle/ui/projects.js +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/oracle/ui/qrcode.js +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/oracle/ui/settings.js +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/oracle/ui/suggestions.js +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/oracle/ui/theme_tabs.js +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/services/__init__.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/services/access_telemetry.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/services/activity_log.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/services/agent_base.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/services/agent_locks.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/services/agents.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/services/artifact_defs.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/services/auto_memory.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/services/background_service.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/services/bench/__init__.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/services/bench/external/__init__.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/services/bench/external/aider_polyglot.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/services/bench/external/swe_bench.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/services/benchmark_dashboard.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/services/bitbucket_client.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/services/bitbucket_credentials.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/services/ci_act.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/services/ci_cache.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/services/ci_expr.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/services/ci_failures.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/services/ci_github.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/services/ci_impact.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/services/ci_intel.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/services/ci_runner.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/services/ci_workflow.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/services/circuit_breaker.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/services/compressor.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/services/context_snapshot.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/services/conversation_store.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/services/cred_audit.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/services/cred_telemetry.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/services/credential_store.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/services/doc_index.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/services/e2e_benchmark.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/services/e2e_evaluator.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/services/e2e_tasks.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/services/edit_ledger.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/services/embedding_index.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/services/enforcement_policy.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/services/error_reporting.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/services/file_memory.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/services/git_context.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/services/hub_service.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/services/indexer.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/services/jira_client.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/services/jira_cloud.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/services/jira_credentials.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/services/jira_data_center.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/services/jira_links.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/services/mask_activation.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/services/mask_mirror.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/services/mask_presets.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/services/memory.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/services/memory_consolidator.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/services/memory_distiller.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/services/memory_graph.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/services/memory_grounder.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/services/memory_queue.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/services/memory_scorer.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/services/metrics.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/services/notifications.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/services/ollama_bridge.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/services/ollama_client.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/services/ollama_credentials.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/services/oracle_service.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/services/output_filter.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/services/override_wake.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/services/parser.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/services/project_manager.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/services/project_runtime.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/services/protocol.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/services/proxy_state.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/services/repo_map.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/services/repo_shape.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/services/retention.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/services/retrieval_broker.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/services/router.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/services/runtime.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/services/scanner.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/services/session_benchmark.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/services/session_manager.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/services/session_preloader.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/services/task_store.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/services/telemetry.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/services/text_index.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/services/time_tracker.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/services/tool_classifier.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/services/transcript_index.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/services/validation_cache.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/services/vector_store.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/services/watcher.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/services/win_subprocess.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/setup.cfg +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_access_builtin_optout.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_access_guard.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_access_guard_shell_project.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_access_guard_surfaces.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_access_guard_wiring.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_activity_reporter.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_agent_locks.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_aider_polyglot.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_antigravity_transition.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_artifact_store.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_artifact_tool.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_background_service.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_bitbucket_cli_smoke.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_bitbucket_client.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_bitbucket_config_fallback.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_bitbucket_credentials.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_bitbucket_tool.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_c3_bridge_project_artifacts.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_chat_poll.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_ci_act.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_ci_cache.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_ci_expr.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_ci_impact.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_ci_intel.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_ci_runner.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_ci_workflow.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_circuit_breaker.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_claude_md_merge.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_cli_smoke.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_compressor_large_file.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_cooccurrence_bounds.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_cred_audit.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_cred_telemetry.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_credential_login_kind.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_credential_store.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_credential_ui_parity.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_credentials_routes.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_credentials_tool.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_creds_cli_smoke.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_delegate_cascade.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_delegate_version_probe.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_e2e_benchmark.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_edit_ledger_deadline.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_edit_ledger_hook.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_edit_locking.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_edit_normalization.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_edit_verify.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_embedding_index_deadlock.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_enforcement_flip.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_enforcement_policy.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_enforcement_routes.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_env_parser.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_failed_calls_do_not_unlock.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_federated_graph.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_filter_backoff.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_ghost_files.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_ghost_generation.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_git_branch_awareness.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_hook_access_guard.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_hook_codex_compat.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_hook_dispatch.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_hook_pretool_enforce.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_hook_prompt_recall.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_hook_smoke.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_hook_state.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_hook_utf8_stdio.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_hub_credentials_route.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_hub_credentials_routes_write.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_hub_enforcement_routes.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_hub_inspect_api.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_hub_locks_routes.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_hub_oracle_service_routes.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_hub_server_smoke.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_hub_subproject_links.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_ide_workflow_adaptation.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_init_clear_preserves_user_content.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_init_scan.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_install_mcp_entrypoint.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_jira_cli_smoke.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_jira_client.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_jira_config_fallback.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_jira_credentials.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_jira_links.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_jira_routes.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_jira_tool.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_lazy_store_init.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_mask_guard.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_mask_routes.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_mask_surfaces.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_mcp_host_guard.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_mcp_memory_timeout.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_mcp_server_smoke.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_mcp_toml.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_memory_distiller.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_memory_graph_api.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_memory_queue.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_memory_system.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_mobile_api.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_mobile_extras.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_mobile_override_routes.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_mobile_security_api.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_no_stale_model_pins.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_notification_dedup.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_notification_discipline.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_ollama_credentials.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_oracle_api_auth.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_oracle_apikey_api.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_oracle_c3_bridge.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_oracle_chat_engine.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_oracle_chat_store.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_oracle_discovery_api.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_oracle_discovery_audit.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_oracle_health_probe.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_oracle_local_auth.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_oracle_ollama_bridge.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_oracle_scanner_cache.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_oracle_security_fixes.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_oracle_session_bootstrap.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_oracle_subproject_awareness.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_oracle_ui_bundle.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_output_filter.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_override_grants_mcp.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_override_wake.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_permissions.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_pm_api.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_project_manager.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_project_manager_merge.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_project_tool.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_read_coercion.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_read_edit_parity.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_related_facts.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_repo_map.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_repo_shape.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_response_boilerplate.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_retention.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_review_digest.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_service_durability.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_session_benchmark.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_session_budget.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_shell_creds.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_shell_robustness.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_shell_write_ledger.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_shell_writes.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_subproject_depth_consumers.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_subproject_exclusion.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_subproject_federation.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_subproject_linkage_api.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_subprojects.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_swe_bench.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_task_store.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_task_tool.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_time_tracker.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_token_telemetry.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_token_tracking.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_tool_registry.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_upgrade_and_version.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_validate.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_vault_write_guard.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_version_sync.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_web_security.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tests/test_windows_reliability.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tui/__init__.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tui/backend.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tui/main.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tui/screens/__init__.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tui/screens/benchmark_view.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tui/screens/claudemd_view.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tui/screens/compress_view.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tui/screens/index_view.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tui/screens/init_view.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tui/screens/mcp_view.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tui/screens/optimize_view.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tui/screens/pipe_view.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tui/screens/projects_view.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tui/screens/search_view.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tui/screens/session_view.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tui/screens/stats.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tui/screens/ui_view.py +0 -0
- {code_context_control-2.96.0 → code_context_control-2.101.0}/tui/theme.tcss +0 -0
{code_context_control-2.96.0/code_context_control.egg-info → code_context_control-2.101.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.101.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.101.0"
|
|
96
96
|
|
|
97
97
|
|
|
98
98
|
def _compress_file_cli(compressor, path, mode="smart", **kw):
|
|
@@ -7266,7 +7266,8 @@ def _access_cmd_list(args, project_path: str) -> None:
|
|
|
7266
7266
|
"project": ".c3/config.json"}
|
|
7267
7267
|
for scope in ("builtin", "global", "project"):
|
|
7268
7268
|
sec = scopes.get(scope) or {}
|
|
7269
|
-
rules = [(k, g) for k in ("deny", "read_only"
|
|
7269
|
+
rules = [(k, g) for k in ("deny", "read_only", "confirm")
|
|
7270
|
+
for g in sec.get(k, [])]
|
|
7270
7271
|
masks = sec.get("mask") or []
|
|
7271
7272
|
print(f"[{scope}] ({notes[scope]}) — {len(rules) + len(masks)} rule(s)")
|
|
7272
7273
|
for kind, glob in rules:
|
|
@@ -7286,12 +7287,22 @@ def _access_cmd_list(args, project_path: str) -> None:
|
|
|
7286
7287
|
for glob in off:
|
|
7287
7288
|
print(f" {'off':<10} {glob}")
|
|
7288
7289
|
print(" re-enable: c3 access builtin enable <glob>")
|
|
7290
|
+
moded = {g: m for g, m in (sec.get("modes") or {}).items()
|
|
7291
|
+
if m not in ("default", "allow")}
|
|
7292
|
+
if moded:
|
|
7293
|
+
print(" MODE set by you (departs from the shipped default):")
|
|
7294
|
+
for glob, m in sorted(moded.items()):
|
|
7295
|
+
print(f" {m:<10} {glob}")
|
|
7296
|
+
print(" reset: c3 access builtin mode <glob> default")
|
|
7289
7297
|
can = [g for g in (sec.get("disableable") or [])
|
|
7290
|
-
if access_guard._norm_builtin(g) not in set(off)
|
|
7298
|
+
if access_guard._norm_builtin(g) not in set(off)
|
|
7299
|
+
and access_guard._norm_builtin(g) not in moded]
|
|
7291
7300
|
if can:
|
|
7292
7301
|
print(" disableable (currently on): "
|
|
7293
7302
|
+ ", ".join(can))
|
|
7294
|
-
print(" disable: c3 access builtin disable <glob>"
|
|
7303
|
+
print(" disable: c3 access builtin disable <glob> · "
|
|
7304
|
+
"granular: c3 access builtin mode <glob> "
|
|
7305
|
+
"{deny,confirm,allow}")
|
|
7295
7306
|
if sec.get("absolute"):
|
|
7296
7307
|
print(" absolute (credential vault, cannot be disabled): "
|
|
7297
7308
|
+ ", ".join(sec["absolute"]))
|
|
@@ -7318,12 +7329,17 @@ def _access_cmd_builtin(args, project_path: str) -> None:
|
|
|
7318
7329
|
|
|
7319
7330
|
action = getattr(args, "builtin_cmd", None)
|
|
7320
7331
|
glob = getattr(args, "glob", None)
|
|
7321
|
-
if action not in ("disable", "enable") or not glob:
|
|
7332
|
+
if action not in ("disable", "enable", "mode") or not glob:
|
|
7322
7333
|
print("Usage: c3 access builtin {disable,enable} <glob>")
|
|
7334
|
+
print(" c3 access builtin mode <glob> {deny,confirm,allow,default}")
|
|
7323
7335
|
print(" disableable: "
|
|
7324
7336
|
+ ", ".join(access_guard.DISABLEABLE_BUILTINS))
|
|
7325
7337
|
return
|
|
7326
7338
|
|
|
7339
|
+
if action == "mode":
|
|
7340
|
+
_access_cmd_builtin_mode(args, glob, project_path)
|
|
7341
|
+
return
|
|
7342
|
+
|
|
7327
7343
|
disabling = action == "disable"
|
|
7328
7344
|
if disabling and not getattr(args, "yes", False):
|
|
7329
7345
|
print(f"About to STOP enforcing the builtin guard on: {glob}")
|
|
@@ -7359,6 +7375,63 @@ def _access_cmd_builtin(args, project_path: str) -> None:
|
|
|
7359
7375
|
"builtin is enforced anyway (config entry removed).")
|
|
7360
7376
|
|
|
7361
7377
|
|
|
7378
|
+
_BUILTIN_MODE_HELP = {
|
|
7379
|
+
"deny": "full block — read, write and enumeration all refuse (tightens "
|
|
7380
|
+
"a write-only guard)",
|
|
7381
|
+
"confirm": "each governed operation pauses and files an approval request "
|
|
7382
|
+
"you answer from the Hub, phone, or `c3 override`",
|
|
7383
|
+
"allow": "the guard stops enforcing entirely (same as disable)",
|
|
7384
|
+
"default": "the shipped behaviour",
|
|
7385
|
+
}
|
|
7386
|
+
|
|
7387
|
+
|
|
7388
|
+
def _access_cmd_builtin_mode(args, glob: str, project_path: str) -> None:
|
|
7389
|
+
"""`c3 access builtin mode <glob> <mode>` — granular builtin control.
|
|
7390
|
+
|
|
7391
|
+
`deny` and `default` never prompt (tightening / reset). `confirm` and
|
|
7392
|
+
`allow` weaken the guard, so they get the same typed-glob beat of
|
|
7393
|
+
friction as `builtin disable`, unless --yes.
|
|
7394
|
+
"""
|
|
7395
|
+
from services import access_guard
|
|
7396
|
+
|
|
7397
|
+
mode = getattr(args, "mode", None)
|
|
7398
|
+
if mode in ("confirm", "allow") and not getattr(args, "yes", False):
|
|
7399
|
+
widening = ("STOP enforcing" if mode == "allow"
|
|
7400
|
+
else "PAUSE (not block) and ask you to approve")
|
|
7401
|
+
print(f"About to make the builtin guard on {glob} {widening}.")
|
|
7402
|
+
if mode == "allow":
|
|
7403
|
+
print(" While off, any agent with C3 tools can touch those paths.")
|
|
7404
|
+
else:
|
|
7405
|
+
print(" Each hit files an Override Request; one tap approves one "
|
|
7406
|
+
"single-use retry.")
|
|
7407
|
+
if glob.endswith("settings*.json") or ".claude" in glob:
|
|
7408
|
+
print(" This guards the file that configures the agent itself — "
|
|
7409
|
+
"hooks, permissions, model.")
|
|
7410
|
+
reply = input("Type the glob again to confirm: ").strip()
|
|
7411
|
+
if reply != glob:
|
|
7412
|
+
print("[abort] Not confirmed; nothing changed.")
|
|
7413
|
+
return
|
|
7414
|
+
|
|
7415
|
+
try:
|
|
7416
|
+
result = access_guard.set_builtin_mode(glob, mode)
|
|
7417
|
+
except ValueError as exc:
|
|
7418
|
+
print(f"[error] {exc}")
|
|
7419
|
+
return
|
|
7420
|
+
|
|
7421
|
+
_access_audit(f"builtin_mode_{result['mode']}", result["glob"],
|
|
7422
|
+
"builtin", "global", project_path)
|
|
7423
|
+
if not result["changed"]:
|
|
7424
|
+
print(f"[=] {result['glob']} — already {result['mode']}")
|
|
7425
|
+
return
|
|
7426
|
+
print(f"[OK] Builtin '{result['glob']}' mode = {result['mode']} "
|
|
7427
|
+
f"(global scope): {_BUILTIN_MODE_HELP[result['mode']]}.")
|
|
7428
|
+
if result["mode"] != "default":
|
|
7429
|
+
print(f" Reset with: c3 access builtin mode {result['glob']} default")
|
|
7430
|
+
if not result["attested"]:
|
|
7431
|
+
print(" [warn] keyring attestation could not be cleared; the "
|
|
7432
|
+
"default is enforced anyway (config entry removed).")
|
|
7433
|
+
|
|
7434
|
+
|
|
7362
7435
|
def _access_cmd_add(args, project_path: str) -> None:
|
|
7363
7436
|
from services import access_guard
|
|
7364
7437
|
|
|
@@ -751,15 +751,19 @@ def build_parser(version: str, parse_cli_ide_arg):
|
|
|
751
751
|
|
|
752
752
|
ac_add = access_subs.add_parser("add", help="Add a rule to the project (or --global) scope")
|
|
753
753
|
ac_add.add_argument("glob", help="POSIX glob (** crosses directories), e.g. 'secrets/**' or '*.pem'")
|
|
754
|
-
ac_add.add_argument("--kind", choices=["deny", "read_only"
|
|
755
|
-
|
|
754
|
+
ac_add.add_argument("--kind", choices=["deny", "read_only", "confirm"],
|
|
755
|
+
required=True,
|
|
756
|
+
help="deny = no read/write/enumerate; read_only = no "
|
|
757
|
+
"write; confirm = writes pause for your approval "
|
|
758
|
+
"(reads unaffected)")
|
|
756
759
|
ac_add.add_argument("--global", dest="use_global", action="store_true",
|
|
757
760
|
help="Store in the global scope (~/.c3) so every C3 project enforces it")
|
|
758
761
|
ac_add.add_argument("--path", dest="project_path", default=".", help="Project directory (default: current)")
|
|
759
762
|
|
|
760
763
|
ac_remove = access_subs.add_parser("remove", help="Remove a rule from the project (or --global) scope")
|
|
761
764
|
ac_remove.add_argument("glob", help="The stored glob to remove (case-insensitive match)")
|
|
762
|
-
ac_remove.add_argument("--kind", choices=["deny", "read_only"
|
|
765
|
+
ac_remove.add_argument("--kind", choices=["deny", "read_only", "confirm"],
|
|
766
|
+
required=True,
|
|
763
767
|
help="Which rule list the glob lives in")
|
|
764
768
|
ac_remove.add_argument("--global", dest="use_global", action="store_true",
|
|
765
769
|
help="Remove from the global scope (~/.c3)")
|
|
@@ -805,6 +809,21 @@ def build_parser(version: str, parse_cli_ide_arg):
|
|
|
805
809
|
_p.add_argument("--yes", action="store_true",
|
|
806
810
|
help="Skip the typed confirmation (scripts/CI)")
|
|
807
811
|
|
|
812
|
+
# Granular per-builtin mode (docs/confirm-guard.md §7): deny tightens a
|
|
813
|
+
# write-deny to a full deny, confirm turns the block into a pause that
|
|
814
|
+
# auto-files an approval request, allow switches it off (same two-key
|
|
815
|
+
# construction as disable), default restores the shipped behaviour.
|
|
816
|
+
bm = builtin_subs.add_parser(
|
|
817
|
+
"mode", help="Set a built-in guard to deny | confirm | allow | default")
|
|
818
|
+
bm.add_argument("glob", help="One of: **/.env*, **/.c3/**, **/.claude/settings*.json, **/.git/**")
|
|
819
|
+
bm.add_argument("mode", choices=["deny", "confirm", "allow", "default"],
|
|
820
|
+
help="deny = full block (tighten); confirm = pause for your "
|
|
821
|
+
"approval; allow = off (two-key); default = shipped behaviour")
|
|
822
|
+
bm.add_argument("--path", dest="project_path", default=".",
|
|
823
|
+
help="Project directory used for the audit log (default: current)")
|
|
824
|
+
bm.add_argument("--yes", action="store_true",
|
|
825
|
+
help="Skip the typed confirmation (scripts/CI)")
|
|
826
|
+
|
|
808
827
|
# ── Mask Guard (v2.63.0, docs/mask-guard.md) ────────────────────────
|
|
809
828
|
# Masking exposes a path but transforms what the agent sees. Rules are
|
|
810
829
|
# human-only, like the rest of Access Guard.
|
|
@@ -221,6 +221,25 @@ def _override_allows(base: str, denial, *, tool: str, op: str, path: str,
|
|
|
221
221
|
return None # fail closed: no grant, ordinary denial
|
|
222
222
|
|
|
223
223
|
|
|
224
|
+
def _confirm_request(base: str, denial, *, tool: str, op: str, path: str,
|
|
225
|
+
session_id: str) -> tuple:
|
|
226
|
+
"""Auto-file an Override Request for a ``confirm`` denial (S8).
|
|
227
|
+
|
|
228
|
+
``(request_id, note)`` — one of them is always ''. Lazy import, never
|
|
229
|
+
raises: a broken request store degrades to S8's "could not be filed"
|
|
230
|
+
tail, and the hold stands either way (docs/confirm-guard.md §3).
|
|
231
|
+
"""
|
|
232
|
+
try:
|
|
233
|
+
from services import override_requests as orq # noqa: PLC0415 — lazy
|
|
234
|
+
row, reason = orq.auto_file(base, denial=denial, tool=tool, op=op,
|
|
235
|
+
path=path, session_id=session_id)
|
|
236
|
+
if row:
|
|
237
|
+
return str(row.get("id") or ""), ""
|
|
238
|
+
return "", reason
|
|
239
|
+
except Exception as exc:
|
|
240
|
+
return "", f"request store unavailable ({exc})"
|
|
241
|
+
|
|
242
|
+
|
|
224
243
|
def _target(tool_input: dict) -> str:
|
|
225
244
|
return str(
|
|
226
245
|
tool_input.get("file_path")
|
|
@@ -348,6 +367,14 @@ def run(payload: dict, project_path: Path | None = None) -> dict | None:
|
|
|
348
367
|
if granted:
|
|
349
368
|
return {"additionalContext": granted}
|
|
350
369
|
_record(denial, tool, op, fp, base, session_id)
|
|
370
|
+
if denial.kind == "confirm":
|
|
371
|
+
# A confirm hold files its own request (grants were consulted
|
|
372
|
+
# above, so an approved retry lands in the granted branch).
|
|
373
|
+
rid, note = _confirm_request(base, denial, tool=tool, op=op,
|
|
374
|
+
path=fp, session_id=session_id)
|
|
375
|
+
return _deny(ag.refusal(denial, fp, op, surface="hook",
|
|
376
|
+
tool=tool, request_id=rid,
|
|
377
|
+
request_note=note))
|
|
351
378
|
return _deny(ag.refusal(denial, fp, op, surface="hook", tool=tool))
|
|
352
379
|
return None
|
|
353
380
|
|
|
@@ -338,6 +338,7 @@ _HUB_JS_FILES = [
|
|
|
338
338
|
"hub_ui/components/hub_cred_audit.js",
|
|
339
339
|
"hub_ui/components/hub_tokens.js",
|
|
340
340
|
"hub_ui/components/hub_locks.js",
|
|
341
|
+
"hub_ui/components/hub_access.js",
|
|
341
342
|
"hub_ui/components/hub_enforcement.js",
|
|
342
343
|
"hub_ui/components/hub_ci.js",
|
|
343
344
|
"hub_ui/components/drill_subprojects.js",
|
|
@@ -3088,6 +3089,212 @@ def api_projects_config_put():
|
|
|
3088
3089
|
return jsonify({"saved": True, "section": section, "config": merged})
|
|
3089
3090
|
|
|
3090
3091
|
|
|
3092
|
+
# ── Override approvals (hub) — docs/override-requests.md P5 desktop parity ──
|
|
3093
|
+
# The desktop half of the request→grant pipeline. Everything here reads or
|
|
3094
|
+
# decides REQUESTS; grants are only ever minted inside override_requests.decide,
|
|
3095
|
+
# and the typed-confirmation checks in the route exist for the client's
|
|
3096
|
+
# benefit — decide() enforces them again regardless of what this route
|
|
3097
|
+
# believes (same two-places-compute-one-enforces rule as the mobile route).
|
|
3098
|
+
|
|
3099
|
+
_OVERRIDE_ROW_FIELDS = (
|
|
3100
|
+
"id", "project_path", "session_id", "created_at", "expires_at", "status",
|
|
3101
|
+
"layer", "rule", "rule_class", "scope", "tool", "op", "path", "refusal",
|
|
3102
|
+
"justification", "resolved_at", "decided_by", "decision_note",
|
|
3103
|
+
)
|
|
3104
|
+
|
|
3105
|
+
|
|
3106
|
+
def _hub_override_row(row: dict) -> dict:
|
|
3107
|
+
"""One request row for the wire. Allowlisted, never the raw dict.
|
|
3108
|
+
|
|
3109
|
+
``path_key`` stays server-side (grant-matching identity; the UI gets the
|
|
3110
|
+
human-readable ``path``). ``justification`` IS shipped — the UI renders it
|
|
3111
|
+
quoted under the untrusted-input label, never as markup.
|
|
3112
|
+
"""
|
|
3113
|
+
out = {k: row.get(k) for k in _OVERRIDE_ROW_FIELDS}
|
|
3114
|
+
for extra in ("grant_id", "grant_mode", "muted"):
|
|
3115
|
+
if row.get(extra) is not None:
|
|
3116
|
+
out[extra] = row.get(extra)
|
|
3117
|
+
return out
|
|
3118
|
+
|
|
3119
|
+
|
|
3120
|
+
def _hub_override_audit(action: str, row: dict, *, confirmed: bool = False,
|
|
3121
|
+
detail_extra: dict | None = None) -> None:
|
|
3122
|
+
"""Identifiers and rule globs only — NEVER the justification (untrusted
|
|
3123
|
+
agent text; the activity feed ships verbatim to every client). Mirrors
|
|
3124
|
+
the mobile route's audit shape with via='hub'. Failure-safe."""
|
|
3125
|
+
detail = {"kind": "override", "action": action,
|
|
3126
|
+
"request_id": row.get("id", ""),
|
|
3127
|
+
"session_id": row.get("session_id", ""),
|
|
3128
|
+
"rule": row.get("rule", ""),
|
|
3129
|
+
"rule_class": row.get("rule_class", ""),
|
|
3130
|
+
"tool": row.get("tool", ""), "op": row.get("op", ""),
|
|
3131
|
+
"via": "hub", "confirmed": bool(confirmed)}
|
|
3132
|
+
detail.update(detail_extra or {})
|
|
3133
|
+
project = row.get("project_path") or ""
|
|
3134
|
+
if not project:
|
|
3135
|
+
return
|
|
3136
|
+
try:
|
|
3137
|
+
ActivityLog(str(project)).log("access_action", dict(detail))
|
|
3138
|
+
except Exception:
|
|
3139
|
+
pass
|
|
3140
|
+
try:
|
|
3141
|
+
from services.edit_ledger import EditLedger
|
|
3142
|
+
EditLedger(str(project)).log_edit(
|
|
3143
|
+
file=f"override://{row.get('id', '')}",
|
|
3144
|
+
change_type=f"override_{action}",
|
|
3145
|
+
summary=(f"{action} override {row.get('id', '')} "
|
|
3146
|
+
f"({row.get('rule', '')}) via Hub"),
|
|
3147
|
+
tags=["override", action], detail=dict(detail))
|
|
3148
|
+
except Exception:
|
|
3149
|
+
pass
|
|
3150
|
+
|
|
3151
|
+
|
|
3152
|
+
@app.route("/api/hub/overrides", methods=["GET"])
|
|
3153
|
+
def api_hub_overrides():
|
|
3154
|
+
"""Pending + recently-decided requests across every project, newest first.
|
|
3155
|
+
|
|
3156
|
+
The hub is this machine's own surface, so unlike the mobile gateway it
|
|
3157
|
+
does not filter rows to a token's project registry — the store is one file
|
|
3158
|
+
across every project on the box and the hub answers for all of them.
|
|
3159
|
+
Each row carries what the card needs to decide without a second fetch:
|
|
3160
|
+
whether the layer is still escalatable and which typed challenge (if any)
|
|
3161
|
+
an approval demands.
|
|
3162
|
+
"""
|
|
3163
|
+
from services import override_policy as opol
|
|
3164
|
+
from services import override_requests as orq
|
|
3165
|
+
project_path = ""
|
|
3166
|
+
raw_project = (request.args.get("path") or "").strip()
|
|
3167
|
+
if raw_project:
|
|
3168
|
+
try:
|
|
3169
|
+
project_path = str(_resolve_project_path(raw_project))
|
|
3170
|
+
except ValueError as e:
|
|
3171
|
+
return jsonify({"error": str(e)}), 404
|
|
3172
|
+
status = (request.args.get("status") or "").strip().lower()
|
|
3173
|
+
try:
|
|
3174
|
+
limit = int(request.args.get("limit") or 50)
|
|
3175
|
+
except (TypeError, ValueError):
|
|
3176
|
+
limit = 50
|
|
3177
|
+
limit = max(1, min(limit, 200))
|
|
3178
|
+
try:
|
|
3179
|
+
rows = orq.list_requests(project_path=project_path, status=status,
|
|
3180
|
+
limit=limit)
|
|
3181
|
+
except Exception as exc:
|
|
3182
|
+
return jsonify({"error": str(exc)}), 500
|
|
3183
|
+
|
|
3184
|
+
out, policies = [], {}
|
|
3185
|
+
for row in rows:
|
|
3186
|
+
proj = str(row.get("project_path") or ".")
|
|
3187
|
+
if proj not in policies:
|
|
3188
|
+
try:
|
|
3189
|
+
policies[proj] = opol.resolve(proj)
|
|
3190
|
+
except Exception:
|
|
3191
|
+
policies[proj] = None
|
|
3192
|
+
policy = policies[proj]
|
|
3193
|
+
rule_class = str(row.get("rule_class") or "")
|
|
3194
|
+
typed = rule_class in opol.TYPED_CONFIRM_LAYERS
|
|
3195
|
+
entry = _hub_override_row(row)
|
|
3196
|
+
entry["needs_typed_confirm"] = typed
|
|
3197
|
+
entry["confirm_with"] = row.get("rule") if typed else ""
|
|
3198
|
+
entry["escalatable"] = bool(policy.escalatable(rule_class)) \
|
|
3199
|
+
if policy is not None else False
|
|
3200
|
+
entry["allow_session_grants"] = bool(policy.allow_session_grants) \
|
|
3201
|
+
if policy is not None else False
|
|
3202
|
+
entry["project_name"] = Path(proj).name
|
|
3203
|
+
out.append(entry)
|
|
3204
|
+
return jsonify({"requests": out, "count": len(out),
|
|
3205
|
+
"project": project_path, "status": status,
|
|
3206
|
+
"limit": limit})
|
|
3207
|
+
|
|
3208
|
+
|
|
3209
|
+
@app.route("/api/hub/overrides/<request_id>", methods=["POST"])
|
|
3210
|
+
def api_hub_override_decide(request_id):
|
|
3211
|
+
"""Approve (minting a grant) or deny one request. decided_by='desktop'.
|
|
3212
|
+
|
|
3213
|
+
Body: {decision, confirm?, mode?, note?, mute?, ttl_s?, uses?}.
|
|
3214
|
+
409 for a request that lapsed while the page was showing it — the card
|
|
3215
|
+
refreshes to the real status instead of silently minting a grant.
|
|
3216
|
+
"""
|
|
3217
|
+
from services import override_policy as opol
|
|
3218
|
+
from services import override_requests as orq
|
|
3219
|
+
data = request.get_json(silent=True) or {}
|
|
3220
|
+
decision = str(data.get("decision") or "").strip().lower()
|
|
3221
|
+
if decision not in (orq.DECISION_APPROVE, orq.DECISION_DENY):
|
|
3222
|
+
return jsonify({"error": "decision must be 'approve' or 'deny'"}), 400
|
|
3223
|
+
mode = str(data.get("mode") or orq.MODE_ONCE).strip().lower()
|
|
3224
|
+
if mode not in orq.MODES:
|
|
3225
|
+
return jsonify({"error": f"mode must be one of: "
|
|
3226
|
+
f"{', '.join(orq.MODES)}"}), 400
|
|
3227
|
+
|
|
3228
|
+
row = orq.get(str(request_id))
|
|
3229
|
+
if row is None:
|
|
3230
|
+
return jsonify({"error": "unknown request"}), 404
|
|
3231
|
+
if row.get("status") != orq.STATUS_PENDING:
|
|
3232
|
+
return jsonify({"error": f"request is {row.get('status')}, not pending",
|
|
3233
|
+
"request": _hub_override_row(row)}), 409
|
|
3234
|
+
|
|
3235
|
+
rule_class = str(row.get("rule_class") or "")
|
|
3236
|
+
confirm = data.get("confirm")
|
|
3237
|
+
if (decision == orq.DECISION_APPROVE
|
|
3238
|
+
and rule_class in opol.TYPED_CONFIRM_LAYERS
|
|
3239
|
+
and confirm != row.get("rule")):
|
|
3240
|
+
return jsonify({
|
|
3241
|
+
"error": f"approving an {rule_class} request needs the rule "
|
|
3242
|
+
"glob retyped by hand",
|
|
3243
|
+
"needs_confirmation": True,
|
|
3244
|
+
"confirm_with": row.get("rule"),
|
|
3245
|
+
}), 400
|
|
3246
|
+
|
|
3247
|
+
try:
|
|
3248
|
+
ttl_s = int(data["ttl_s"]) if data.get("ttl_s") is not None else None
|
|
3249
|
+
uses = int(data["uses"]) if data.get("uses") is not None else None
|
|
3250
|
+
except (TypeError, ValueError):
|
|
3251
|
+
return jsonify({"error": "ttl_s and uses must be integers"}), 400
|
|
3252
|
+
|
|
3253
|
+
try:
|
|
3254
|
+
result = orq.decide(
|
|
3255
|
+
str(request_id), decision, uses=uses, ttl_s=ttl_s,
|
|
3256
|
+
note=str(data.get("note") or ""), decided_by="desktop",
|
|
3257
|
+
confirm=confirm, mode=mode, mute=bool(data.get("mute")))
|
|
3258
|
+
except orq.OverrideError as exc:
|
|
3259
|
+
_hub_override_audit(f"{decision}_refused", row)
|
|
3260
|
+
return jsonify({"error": str(exc)}), 400
|
|
3261
|
+
except Exception as exc:
|
|
3262
|
+
return jsonify({"error": str(exc)}), 500
|
|
3263
|
+
|
|
3264
|
+
_hub_override_audit(decision, result,
|
|
3265
|
+
confirmed=rule_class in opol.TYPED_CONFIRM_LAYERS,
|
|
3266
|
+
detail_extra={"mode": mode,
|
|
3267
|
+
"grant_id": result.get("grant_id", "")})
|
|
3268
|
+
return jsonify({"request": _hub_override_row(result),
|
|
3269
|
+
"decision": decision})
|
|
3270
|
+
|
|
3271
|
+
|
|
3272
|
+
@app.route("/api/hub/access", methods=["GET"])
|
|
3273
|
+
def api_hub_access():
|
|
3274
|
+
"""Effective Access Guard rules + override policy for one project.
|
|
3275
|
+
|
|
3276
|
+
Read-only companion to the approvals list: the per-project mode matrix
|
|
3277
|
+
the tab renders under the pending cards. Rule MUTATION stays on the
|
|
3278
|
+
per-project server and the CLI — this route never writes.
|
|
3279
|
+
"""
|
|
3280
|
+
from services import access_guard
|
|
3281
|
+
from services import override_policy as opol
|
|
3282
|
+
raw = (request.args.get("path") or "").strip()
|
|
3283
|
+
if not raw:
|
|
3284
|
+
return jsonify({"error": "path is required"}), 400
|
|
3285
|
+
try:
|
|
3286
|
+
resolved = _resolve_project_path(raw)
|
|
3287
|
+
except ValueError as e:
|
|
3288
|
+
return jsonify({"error": str(e)}), 404
|
|
3289
|
+
try:
|
|
3290
|
+
rules = access_guard.list_rules(str(resolved))
|
|
3291
|
+
policy = opol.resolve(str(resolved)).as_dict()
|
|
3292
|
+
except Exception as exc:
|
|
3293
|
+
return jsonify({"error": str(exc)}), 500
|
|
3294
|
+
return jsonify({"path": str(resolved), "rules": rules,
|
|
3295
|
+
"policy": policy})
|
|
3296
|
+
|
|
3297
|
+
|
|
3091
3298
|
# ── Project management: tasks / milestones / notes (v2.45.0) ──────────────
|
|
3092
3299
|
# Direct TaskStore per request (reload-per-op store — no runtime build needed
|
|
3093
3300
|
# for mutations); every write audited to the target project's activity log.
|
|
@@ -44,7 +44,7 @@ function App() {
|
|
|
44
44
|
if (cfg.projects_view === 'grid') setView('grid');
|
|
45
45
|
if (cfg.sidebar_collapsed != null) setSidebarCollapsed(!!cfg.sidebar_collapsed);
|
|
46
46
|
if (cfg.sidebar_group) setFilter(cfg.sidebar_group);
|
|
47
|
-
if (['board', 'ci', 'creds', 'locks', 'enforce'].includes(cfg.main_view)) setMainView(cfg.main_view);
|
|
47
|
+
if (['board', 'ci', 'creds', 'tokens', 'locks', 'access', 'enforce'].includes(cfg.main_view)) setMainView(cfg.main_view);
|
|
48
48
|
} catch { }
|
|
49
49
|
try { const v = await api.get('/api/version'); setVersion(v.c3_version || ''); } catch { }
|
|
50
50
|
}, []);
|
|
@@ -120,6 +120,8 @@ function App() {
|
|
|
120
120
|
<HubTokens projects={projects} onOpenDrill={openDrill} />
|
|
121
121
|
) : mainView === 'locks' ? (
|
|
122
122
|
<HubLocks projects={projects} onOpenDrill={openDrill} />
|
|
123
|
+
) : mainView === 'access' ? (
|
|
124
|
+
<HubAccess projects={projects} />
|
|
123
125
|
) : mainView === 'enforce' ? (
|
|
124
126
|
<HubEnforcement projects={projects} onOpenDrill={openDrill} />
|
|
125
127
|
) : (
|