code-context-control 2.61.2__tar.gz → 2.63.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.61.2 → code_context_control-2.63.0}/PKG-INFO +40 -1
- {code_context_control-2.61.2 → code_context_control-2.63.0}/README.md +39 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/cli/_hook_utils.py +22 -1
- {code_context_control-2.61.2 → code_context_control-2.63.0}/cli/c3.py +313 -5
- {code_context_control-2.61.2 → code_context_control-2.63.0}/cli/commands/parser.py +78 -0
- code_context_control-2.63.0/cli/guide/access.html +289 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/cli/guide/bitbucket.html +2 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/cli/guide/credentials.html +2 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/cli/guide/getting-started.html +2 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/cli/guide/index.html +18 -0
- code_context_control-2.63.0/cli/guide/masking.html +400 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/cli/guide/oracle.html +2 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/cli/guide/tools.html +2 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/cli/guide/workflow.html +2 -0
- code_context_control-2.63.0/cli/hook_access_guard.py +119 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/cli/hook_dispatch.py +35 -3
- {code_context_control-2.61.2 → code_context_control-2.63.0}/cli/hook_pretool_enforce.py +14 -2
- {code_context_control-2.61.2 → code_context_control-2.63.0}/cli/hub_server.py +6 -2
- {code_context_control-2.61.2 → code_context_control-2.63.0}/cli/mcp_server.py +7 -3
- {code_context_control-2.61.2 → code_context_control-2.63.0}/cli/server.py +217 -1
- {code_context_control-2.61.2 → code_context_control-2.63.0}/cli/tools/artifacts.py +8 -1
- {code_context_control-2.61.2 → code_context_control-2.63.0}/cli/tools/compress.py +46 -1
- {code_context_control-2.61.2 → code_context_control-2.63.0}/cli/tools/delegate.py +60 -1
- {code_context_control-2.61.2 → code_context_control-2.63.0}/cli/tools/edit.py +11 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/cli/tools/filter.py +8 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/cli/tools/impact.py +20 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/cli/tools/project.py +88 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/cli/tools/read.py +37 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/cli/tools/search.py +65 -17
- {code_context_control-2.61.2 → code_context_control-2.63.0}/cli/tools/shell.py +131 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/cli/tools/status.py +31 -1
- {code_context_control-2.61.2 → code_context_control-2.63.0}/cli/tools/validate.py +13 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/cli/ui/app.js +4 -0
- code_context_control-2.63.0/cli/ui/components/access.js +675 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/code_context_control.egg-info/PKG-INFO +40 -1
- {code_context_control-2.61.2 → code_context_control-2.63.0}/code_context_control.egg-info/SOURCES.txt +17 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/pyproject.toml +1 -1
- code_context_control-2.63.0/services/access_guard.py +962 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/services/artifact_store.py +19 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/services/auto_memory.py +25 -7
- {code_context_control-2.61.2 → code_context_control-2.63.0}/services/claude_md.py +1 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/services/compressor.py +60 -2
- {code_context_control-2.61.2 → code_context_control-2.63.0}/services/file_memory.py +23 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/services/indexer.py +40 -1
- code_context_control-2.63.0/services/mask_activation.py +295 -0
- code_context_control-2.63.0/services/mask_mirror.py +341 -0
- code_context_control-2.63.0/services/mask_presets.py +293 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/services/memory.py +71 -1
- {code_context_control-2.61.2 → code_context_control-2.63.0}/services/scanner.py +45 -0
- code_context_control-2.63.0/tests/test_access_guard.py +293 -0
- code_context_control-2.63.0/tests/test_access_guard_meta.py +157 -0
- code_context_control-2.63.0/tests/test_access_guard_shell_project.py +379 -0
- code_context_control-2.63.0/tests/test_access_guard_surfaces.py +335 -0
- code_context_control-2.63.0/tests/test_access_guard_wiring.py +330 -0
- code_context_control-2.63.0/tests/test_hook_access_guard.py +184 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/tests/test_hook_dispatch.py +6 -4
- {code_context_control-2.61.2 → code_context_control-2.63.0}/tests/test_hook_pretool_enforce.py +1 -1
- {code_context_control-2.61.2 → code_context_control-2.63.0}/tests/test_hook_smoke.py +2 -2
- {code_context_control-2.61.2 → code_context_control-2.63.0}/tests/test_hook_state.py +4 -3
- code_context_control-2.63.0/tests/test_mask_guard.py +496 -0
- code_context_control-2.63.0/tests/test_mask_routes.py +207 -0
- code_context_control-2.63.0/tests/test_mask_surfaces.py +256 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/LICENSE +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/cli/__init__.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/cli/commands/__init__.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/cli/commands/common.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/cli/docs.html +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/cli/edits.html +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/cli/guide/shared.css +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/cli/hook_artifact.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/cli/hook_auto_snapshot.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/cli/hook_c3_signal.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/cli/hook_c3read.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/cli/hook_edit_ledger.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/cli/hook_edit_unlock.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/cli/hook_filter.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/cli/hook_ghost_files.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/cli/hook_prompt_recall.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/cli/hook_read.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/cli/hook_session_stats.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/cli/hook_terse_advisor.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/cli/hub.html +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/cli/hub_ui/app.js +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/cli/hub_ui/components/add_project.js +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/cli/hub_ui/components/config_editor.js +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/cli/hub_ui/components/drill_artifacts.js +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/cli/hub_ui/components/drill_health.js +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/cli/hub_ui/components/drill_panel.js +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/cli/hub_ui/components/drill_subprojects.js +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/cli/hub_ui/components/drill_tasks.js +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/cli/hub_ui/components/drill_views.js +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/cli/hub_ui/components/global_search.js +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/cli/hub_ui/components/hub_credentials.js +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/cli/hub_ui/components/mcp_manager.js +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/cli/hub_ui/components/modals.js +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/cli/hub_ui/components/project_card.js +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/cli/hub_ui/components/project_tree.js +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/cli/hub_ui/components/session_drawer.js +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/cli/hub_ui/components/settings_modal.js +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/cli/hub_ui/components/sidebar.js +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/cli/hub_ui/components/summary_bar.js +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/cli/hub_ui/components/task_board.js +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/cli/hub_ui/components/toasts.js +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/cli/hub_ui/components/topbar.js +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/cli/hub_ui/state.js +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/cli/hub_ui.html +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/cli/mcp_proxy.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/cli/progress.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/cli/tools/__init__.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/cli/tools/_helpers.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/cli/tools/agent.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/cli/tools/bitbucket.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/cli/tools/credentials.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/cli/tools/edits.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/cli/tools/federate.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/cli/tools/jira.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/cli/tools/memory.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/cli/tools/session.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/cli/tools/tasks.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/cli/ui/api.js +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/cli/ui/components/bitbucket.js +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/cli/ui/components/chat.js +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/cli/ui/components/credentials.js +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/cli/ui/components/dashboard.js +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/cli/ui/components/edits.js +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/cli/ui/components/instructions.js +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/cli/ui/components/jira.js +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/cli/ui/components/memory.js +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/cli/ui/components/sessions.js +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/cli/ui/components/settings.js +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/cli/ui/components/sidebar.js +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/cli/ui/components/tasks.js +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/cli/ui/icons.js +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/cli/ui/pm_shared.js +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/cli/ui/shared.js +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/cli/ui/theme.js +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/cli/ui.html +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/cli/ui_legacy.html +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/cli/ui_nano.html +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/code_context_control.egg-info/dependency_links.txt +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/code_context_control.egg-info/entry_points.txt +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/code_context_control.egg-info/requires.txt +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/code_context_control.egg-info/top_level.txt +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/core/__init__.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/core/config.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/core/ide.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/core/mcp_toml.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/core/web_security.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/oracle/__init__.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/oracle/config.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/oracle/mcp_oracle.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/oracle/oracle_server.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/oracle/oracle_ui.html +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/oracle/services/__init__.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/oracle/services/activity_reporter.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/oracle/services/api_auth.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/oracle/services/c3_bridge.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/oracle/services/chat_engine.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/oracle/services/chat_store.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/oracle/services/cross_memory.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/oracle/services/federated_graph.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/oracle/services/health_checker.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/oracle/services/insight_engine.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/oracle/services/local_session.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/oracle/services/memory_reader.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/oracle/services/memory_writer.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/oracle/services/project_scanner.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/oracle/services/review_agent.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/oracle/services/tool_executor.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/oracle/services/tool_registry.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/oracle/ui/activity.js +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/oracle/ui/agents.js +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/oracle/ui/app.js +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/oracle/ui/busy.js +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/oracle/ui/chat/conversations.js +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/oracle/ui/chat/input.js +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/oracle/ui/chat/markdown.js +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/oracle/ui/chat/send.js +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/oracle/ui/chat/stream_renderer.js +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/oracle/ui/chat/toolbar.js +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/oracle/ui/core.js +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/oracle/ui/crossgraph.js +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/oracle/ui/header.js +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/oracle/ui/insights.js +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/oracle/ui/projects.js +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/oracle/ui/settings.js +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/oracle/ui/suggestions.js +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/oracle/ui/theme_tabs.js +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/services/__init__.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/services/activity_log.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/services/agent_base.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/services/agents.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/services/artifact_defs.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/services/bench/__init__.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/services/bench/external/__init__.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/services/bench/external/aider_polyglot.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/services/bench/external/swe_bench.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/services/benchmark_dashboard.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/services/bitbucket_client.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/services/bitbucket_credentials.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/services/circuit_breaker.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/services/context_snapshot.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/services/conversation_store.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/services/credential_store.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/services/doc_index.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/services/e2e_benchmark.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/services/e2e_evaluator.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/services/e2e_tasks.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/services/edit_ledger.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/services/embedding_index.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/services/error_reporting.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/services/git_context.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/services/hub_service.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/services/jira_client.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/services/jira_cloud.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/services/jira_credentials.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/services/jira_data_center.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/services/jira_links.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/services/memory_consolidator.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/services/memory_distiller.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/services/memory_graph.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/services/memory_grounder.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/services/memory_queue.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/services/memory_scorer.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/services/metrics.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/services/notifications.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/services/ollama_bridge.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/services/ollama_client.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/services/ollama_credentials.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/services/output_filter.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/services/parser.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/services/project_manager.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/services/project_runtime.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/services/protocol.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/services/proxy_state.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/services/repo_map.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/services/retention.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/services/retrieval_broker.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/services/router.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/services/runtime.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/services/session_benchmark.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/services/session_manager.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/services/session_preloader.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/services/subprojects.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/services/task_store.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/services/telemetry.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/services/text_index.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/services/time_tracker.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/services/tool_classifier.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/services/transcript_index.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/services/validation_cache.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/services/vector_store.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/services/watcher.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/services/win_subprocess.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/setup.cfg +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/tests/test_activity_reporter.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/tests/test_aider_polyglot.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/tests/test_antigravity_transition.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/tests/test_artifact_store.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/tests/test_artifact_tool.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/tests/test_bitbucket_cli_smoke.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/tests/test_bitbucket_client.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/tests/test_bitbucket_config_fallback.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/tests/test_bitbucket_credentials.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/tests/test_bitbucket_tool.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/tests/test_c3_bridge_project_artifacts.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/tests/test_c3_shell.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/tests/test_circuit_breaker.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/tests/test_claude_md_merge.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/tests/test_cli_smoke.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/tests/test_compressor_large_file.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/tests/test_credential_store.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/tests/test_credentials_routes.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/tests/test_credentials_tool.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/tests/test_creds_cli_smoke.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/tests/test_delegate_cascade.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/tests/test_e2e_benchmark.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/tests/test_edit_ledger_hook.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/tests/test_edit_normalization.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/tests/test_enforcement_flip.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/tests/test_federated_graph.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/tests/test_filter_backoff.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/tests/test_ghost_files.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/tests/test_ghost_generation.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/tests/test_git_branch_awareness.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/tests/test_hook_prompt_recall.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/tests/test_hook_utf8_stdio.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/tests/test_hub_credentials_route.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/tests/test_hub_credentials_routes_write.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/tests/test_hub_inspect_api.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/tests/test_hub_server_smoke.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/tests/test_hub_subproject_links.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/tests/test_init_scan.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/tests/test_install_mcp_entrypoint.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/tests/test_jira_cli_smoke.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/tests/test_jira_client.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/tests/test_jira_config_fallback.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/tests/test_jira_credentials.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/tests/test_jira_links.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/tests/test_jira_routes.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/tests/test_jira_tool.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/tests/test_lazy_store_init.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/tests/test_mcp_host_guard.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/tests/test_mcp_memory_timeout.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/tests/test_mcp_server_smoke.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/tests/test_mcp_toml.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/tests/test_memory_distiller.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/tests/test_memory_graph_api.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/tests/test_memory_queue.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/tests/test_memory_system.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/tests/test_no_stale_model_pins.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/tests/test_notification_dedup.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/tests/test_notification_discipline.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/tests/test_ollama_credentials.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/tests/test_oracle_api_auth.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/tests/test_oracle_apikey_api.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/tests/test_oracle_c3_bridge.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/tests/test_oracle_chat_engine.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/tests/test_oracle_discovery_api.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/tests/test_oracle_local_auth.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/tests/test_oracle_ollama_bridge.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/tests/test_oracle_scanner_cache.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/tests/test_oracle_security_fixes.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/tests/test_oracle_subproject_awareness.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/tests/test_oracle_ui_bundle.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/tests/test_output_filter.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/tests/test_permissions.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/tests/test_pm_api.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/tests/test_project_manager.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/tests/test_project_manager_merge.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/tests/test_project_tool.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/tests/test_read_coercion.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/tests/test_read_edit_parity.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/tests/test_related_facts.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/tests/test_repo_map.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/tests/test_response_boilerplate.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/tests/test_retention.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/tests/test_review_digest.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/tests/test_service_durability.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/tests/test_session_benchmark.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/tests/test_session_budget.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/tests/test_shell_creds.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/tests/test_shell_robustness.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/tests/test_subproject_exclusion.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/tests/test_subproject_federation.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/tests/test_subprojects.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/tests/test_swe_bench.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/tests/test_task_store.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/tests/test_task_tool.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/tests/test_time_tracker.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/tests/test_token_telemetry.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/tests/test_tool_registry.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/tests/test_upgrade_and_version.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/tests/test_validate.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/tests/test_vault_write_guard.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/tests/test_version_sync.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/tests/test_web_security.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/tests/test_windows_reliability.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/tui/__init__.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/tui/backend.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/tui/main.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/tui/screens/__init__.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/tui/screens/benchmark_view.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/tui/screens/claudemd_view.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/tui/screens/compress_view.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/tui/screens/index_view.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/tui/screens/init_view.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/tui/screens/mcp_view.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/tui/screens/optimize_view.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/tui/screens/pipe_view.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/tui/screens/projects_view.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/tui/screens/search_view.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/tui/screens/session_view.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/tui/screens/stats.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.0}/tui/screens/ui_view.py +0 -0
- {code_context_control-2.61.2 → code_context_control-2.63.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.63.0
|
|
4
4
|
Summary: Local code-intelligence layer for AI coding tools (Claude Code, Codex, Copilot, Cursor, Antigravity). Retrieve less, read less, edit safer — version the configs that shape your agent (CLAUDE.md, skills, hooks, MCP), and manage multi-project + sub-project hierarchies from a local hub.
|
|
5
5
|
Author-email: Dimitri Tselenchuk <dtselenc@gmail.com>
|
|
6
6
|
License-Expression: Apache-2.0
|
|
@@ -386,6 +386,45 @@ inbound-only, **no hub route ever returns a stored value** (there is no
|
|
|
386
386
|
Full documentation: [`cli/guide/credentials.html`](cli/guide/credentials.html)
|
|
387
387
|
— open it in the app at `/guide/credentials.html`.
|
|
388
388
|
|
|
389
|
+
### Access Guard (v2.62.0)
|
|
390
|
+
|
|
391
|
+
The Credential Vault protects *values*; **Access Guard** protects *files and
|
|
392
|
+
folders*. Two glob lists in your config mark what an agent must never read
|
|
393
|
+
(`deny`) or never write (`read_only`), and one shared evaluator enforces them
|
|
394
|
+
at every C3 surface — the MCP tools (`c3_read`/`c3_edit`/`c3_search`/…, so
|
|
395
|
+
any agent using C3 is covered), Claude Code's native tools via PreToolUse
|
|
396
|
+
hooks (fail-closed: a broken guard denies writes instead of waving them
|
|
397
|
+
through), and `c3_shell` via a best-effort command scan.
|
|
398
|
+
|
|
399
|
+
```bash
|
|
400
|
+
c3 access add "secrets/**" --kind deny # never read, never write
|
|
401
|
+
c3 access add "migrations/**" --kind read_only
|
|
402
|
+
c3 access check secrets/key.txt # probe: verdict + matched rule
|
|
403
|
+
```
|
|
404
|
+
|
|
405
|
+
- **Tighten-only.** No allow list exists; scopes (global `~/.c3` + project
|
|
406
|
+
`.c3`) merge as a union. A cloned repo's config can only add protection,
|
|
407
|
+
never grant itself access.
|
|
408
|
+
- **`deny` means deny-create and deny-enumerate** too: alternate spellings
|
|
409
|
+
are canonicalized before matching, and denied paths never appear in search
|
|
410
|
+
results, maps, or the vector index.
|
|
411
|
+
- **Refusals teach the agent to stop.** Every denial carries a stable
|
|
412
|
+
`[c3-access:*]` tag, the matched rule and scope, and explicit
|
|
413
|
+
do-not-retry guidance — no retry loops, no "file must not exist, let me
|
|
414
|
+
recreate it".
|
|
415
|
+
- **All rule changes are human-only** (Access Guard UI tab or `c3 access`
|
|
416
|
+
CLI), ledger-logged; agents have no mutation surface.
|
|
417
|
+
- **Built-ins always on:** `.env*` files, the credential vault's sidecars,
|
|
418
|
+
and write-denies on `.c3/`, `.claude/settings*.json`, `.git/`, and the
|
|
419
|
+
installed C3 package itself.
|
|
420
|
+
- **Honest coverage:** this guards *cooperative* agents against mistakes and
|
|
421
|
+
prompt-injection. It is not a sandbox — raw shell or direct file access
|
|
422
|
+
outside C3's tools and hooks is not stopped. The guide states exactly
|
|
423
|
+
where each layer holds.
|
|
424
|
+
|
|
425
|
+
Full documentation: [`cli/guide/access.html`](cli/guide/access.html)
|
|
426
|
+
— open it in the app at `/guide/access.html`.
|
|
427
|
+
|
|
389
428
|
### Jira — Cloud + Data Center (v2.56.0)
|
|
390
429
|
|
|
391
430
|
`c3_jira` connects to Jira Cloud (REST v3, email + API token) or self-hosted
|
|
@@ -323,6 +323,45 @@ inbound-only, **no hub route ever returns a stored value** (there is no
|
|
|
323
323
|
Full documentation: [`cli/guide/credentials.html`](cli/guide/credentials.html)
|
|
324
324
|
— open it in the app at `/guide/credentials.html`.
|
|
325
325
|
|
|
326
|
+
### Access Guard (v2.62.0)
|
|
327
|
+
|
|
328
|
+
The Credential Vault protects *values*; **Access Guard** protects *files and
|
|
329
|
+
folders*. Two glob lists in your config mark what an agent must never read
|
|
330
|
+
(`deny`) or never write (`read_only`), and one shared evaluator enforces them
|
|
331
|
+
at every C3 surface — the MCP tools (`c3_read`/`c3_edit`/`c3_search`/…, so
|
|
332
|
+
any agent using C3 is covered), Claude Code's native tools via PreToolUse
|
|
333
|
+
hooks (fail-closed: a broken guard denies writes instead of waving them
|
|
334
|
+
through), and `c3_shell` via a best-effort command scan.
|
|
335
|
+
|
|
336
|
+
```bash
|
|
337
|
+
c3 access add "secrets/**" --kind deny # never read, never write
|
|
338
|
+
c3 access add "migrations/**" --kind read_only
|
|
339
|
+
c3 access check secrets/key.txt # probe: verdict + matched rule
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
- **Tighten-only.** No allow list exists; scopes (global `~/.c3` + project
|
|
343
|
+
`.c3`) merge as a union. A cloned repo's config can only add protection,
|
|
344
|
+
never grant itself access.
|
|
345
|
+
- **`deny` means deny-create and deny-enumerate** too: alternate spellings
|
|
346
|
+
are canonicalized before matching, and denied paths never appear in search
|
|
347
|
+
results, maps, or the vector index.
|
|
348
|
+
- **Refusals teach the agent to stop.** Every denial carries a stable
|
|
349
|
+
`[c3-access:*]` tag, the matched rule and scope, and explicit
|
|
350
|
+
do-not-retry guidance — no retry loops, no "file must not exist, let me
|
|
351
|
+
recreate it".
|
|
352
|
+
- **All rule changes are human-only** (Access Guard UI tab or `c3 access`
|
|
353
|
+
CLI), ledger-logged; agents have no mutation surface.
|
|
354
|
+
- **Built-ins always on:** `.env*` files, the credential vault's sidecars,
|
|
355
|
+
and write-denies on `.c3/`, `.claude/settings*.json`, `.git/`, and the
|
|
356
|
+
installed C3 package itself.
|
|
357
|
+
- **Honest coverage:** this guards *cooperative* agents against mistakes and
|
|
358
|
+
prompt-injection. It is not a sandbox — raw shell or direct file access
|
|
359
|
+
outside C3's tools and hooks is not stopped. The guide states exactly
|
|
360
|
+
where each layer holds.
|
|
361
|
+
|
|
362
|
+
Full documentation: [`cli/guide/access.html`](cli/guide/access.html)
|
|
363
|
+
— open it in the app at `/guide/access.html`.
|
|
364
|
+
|
|
326
365
|
### Jira — Cloud + Data Center (v2.56.0)
|
|
327
366
|
|
|
328
367
|
`c3_jira` connects to Jira Cloud (REST v3, email + API token) or self-hosted
|
|
@@ -175,6 +175,17 @@ def load_enforcement_state(project_path: Path | None = None, session_id: str = "
|
|
|
175
175
|
# session must not grant unlocks (signal files used to survive /clear).
|
|
176
176
|
if session_id and state.get("session_id") and state["session_id"] != session_id:
|
|
177
177
|
return _empty_state(session_id)
|
|
178
|
+
# Migrate unlock keys written before canonical_key (raw resolve() form):
|
|
179
|
+
# lookups are canonical now, so re-key at load — old and new forms merge.
|
|
180
|
+
migrated: dict = {}
|
|
181
|
+
for k, cats in state.get("unlocked_files", {}).items():
|
|
182
|
+
try:
|
|
183
|
+
key = canonical_key(k)
|
|
184
|
+
except OSError:
|
|
185
|
+
continue
|
|
186
|
+
merged = set(migrated.get(key, [])) | set(cats)
|
|
187
|
+
migrated[key] = sorted(merged)
|
|
188
|
+
state["unlocked_files"] = migrated
|
|
178
189
|
return state
|
|
179
190
|
|
|
180
191
|
|
|
@@ -205,6 +216,16 @@ def record_c3_signal(
|
|
|
205
216
|
save_enforcement_state(state, project_path)
|
|
206
217
|
|
|
207
218
|
|
|
219
|
+
def canonical_key(path) -> str:
|
|
220
|
+
"""Canonical unlock-map key: resolved, forward-slash, casefolded.
|
|
221
|
+
|
|
222
|
+
Must stay form-identical to services.access_guard.canonicalize()'s canon
|
|
223
|
+
string for existing paths (parity-tested) — the unlock map and the
|
|
224
|
+
access evaluator must never disagree about path identity on Windows.
|
|
225
|
+
"""
|
|
226
|
+
return str(Path(path).resolve()).replace("\\", "/").casefold()
|
|
227
|
+
|
|
228
|
+
|
|
208
229
|
def record_unlocked_files(
|
|
209
230
|
paths,
|
|
210
231
|
categories,
|
|
@@ -223,7 +244,7 @@ def record_unlocked_files(
|
|
|
223
244
|
if not fp:
|
|
224
245
|
continue
|
|
225
246
|
try:
|
|
226
|
-
normalized =
|
|
247
|
+
normalized = canonical_key(fp)
|
|
227
248
|
except OSError:
|
|
228
249
|
continue
|
|
229
250
|
cats = set(state["unlocked_files"].get(normalized, []))
|
|
@@ -92,7 +92,17 @@ 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.63.0"
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def _compress_file_cli(compressor, path, mode="smart", **kw):
|
|
99
|
+
"""compress_file for human-CLI paths: AccessDenied → error dict, not a
|
|
100
|
+
traceback. The refusal text names the rule so the operator can act."""
|
|
101
|
+
from services import access_guard as _ag
|
|
102
|
+
try:
|
|
103
|
+
return compressor.compress_file(path, mode, **kw)
|
|
104
|
+
except _ag.AccessDenied as exc:
|
|
105
|
+
return {"error": exc.message}
|
|
96
106
|
|
|
97
107
|
|
|
98
108
|
def _command_deps() -> CommandDeps:
|
|
@@ -1338,7 +1348,7 @@ def _benchmark_extract_preview(full_path: Path, compressor: CodeCompressor, patt
|
|
|
1338
1348
|
extracted = ""
|
|
1339
1349
|
|
|
1340
1350
|
if ext in code_exts and not pattern:
|
|
1341
|
-
result = compressor
|
|
1351
|
+
result = _compress_file_cli(compressor, str(full_path), "smart")
|
|
1342
1352
|
extracted = result.get("compressed", "") if "error" not in result else f"Error: {result['error']}"
|
|
1343
1353
|
|
|
1344
1354
|
elif ext == ".jsonl" and not pattern:
|
|
@@ -1617,7 +1627,7 @@ def _benchmark_delegate_optional(project_path: Path, sample: list[tuple[Path, st
|
|
|
1617
1627
|
"Focus on responsibilities, important functions/classes, and notable dependencies."
|
|
1618
1628
|
)
|
|
1619
1629
|
|
|
1620
|
-
compressed_result = compressor
|
|
1630
|
+
compressed_result = _compress_file_cli(compressor, str(fpath), "smart")
|
|
1621
1631
|
compressed_context = compressed_result.get("compressed", "") if isinstance(compressed_result, dict) else ""
|
|
1622
1632
|
if not compressed_context:
|
|
1623
1633
|
compressed_context = raw_content
|
|
@@ -3478,7 +3488,7 @@ def cmd_benchmark(args):
|
|
|
3478
3488
|
raw_content = content
|
|
3479
3489
|
comp_baseline_latencies.append((time.perf_counter() - t_read) * 1000)
|
|
3480
3490
|
t0 = time.perf_counter()
|
|
3481
|
-
result = compressor
|
|
3491
|
+
result = _compress_file_cli(compressor, str(fpath), "smart")
|
|
3482
3492
|
comp_c3_latencies.append((time.perf_counter() - t0) * 1000)
|
|
3483
3493
|
raw_tokens = count_tokens(raw_content)
|
|
3484
3494
|
comp_orig += raw_tokens
|
|
@@ -3544,7 +3554,7 @@ def cmd_benchmark(args):
|
|
|
3544
3554
|
tmp.write(raw_extracted)
|
|
3545
3555
|
tmp_path = tmp.name
|
|
3546
3556
|
try:
|
|
3547
|
-
comp_res = compressor
|
|
3557
|
+
comp_res = _compress_file_cli(compressor, tmp_path, mode="smart")
|
|
3548
3558
|
extracted_text += comp_res.get("compressed", raw_extracted)
|
|
3549
3559
|
finally:
|
|
3550
3560
|
if os.path.exists(tmp_path):
|
|
@@ -4660,6 +4670,7 @@ back to native tools as the task progresses.
|
|
|
4660
4670
|
- **Delegate**: `c3_delegate(task, backend='ollama|codex|gemini|claude|auto')` — offload to other models
|
|
4661
4671
|
- **Bitbucket** (v2.30.0+, when `c3 bitbucket login` has run): `c3_bitbucket(action='list_prs|get_pr|merge_pr|...')` — self-hosted Bitbucket Data Center / Server. Token in OS keyring; mutating actions auto-log to the edit ledger.
|
|
4662
4672
|
- **Cross-project** (v2.31.0+): `c3_project(action='list|scan|search|read|edit|...', project='<name|path>')` — discover and operate on OTHER c3-installed projects. Reads run freely; writes (edit/shell/memory) need `allow_write=true`.
|
|
4673
|
+
- **Masked paths** (v2.63.0+): content prefixed `[c3-mask:transformed]` is a policy-transformed VIEW, not the file. Values may be synthetic, rows withheld, bodies stripped — don't copy literals out of it or infer completeness from it. Masked paths are read-only and refuse shell/git/validate/impact/filter/delegate (`[c3-mask:unsupported]`). That's policy, not a transient error — report the block instead of routing around it.
|
|
4663
4674
|
|
|
4664
4675
|
## Self-Check
|
|
4665
4676
|
If you haven't called a c3_* tool in several turns during active development, re-engage
|
|
@@ -5203,6 +5214,9 @@ def cmd_install_mcp(args):
|
|
|
5203
5214
|
]
|
|
5204
5215
|
|
|
5205
5216
|
# ── PreToolUse hooks (enforcement — blocks native tools without prior c3_*) ──
|
|
5217
|
+
# Bash/run_shell_command joined in v2.62: the Access Guard sub-hook
|
|
5218
|
+
# scans shell commands (best-effort); without these matchers PreToolUse
|
|
5219
|
+
# simply never fires for shell — proven bypass, see docs/access-guard.md.
|
|
5206
5220
|
_pre_matcher_names = [
|
|
5207
5221
|
read_matcher,
|
|
5208
5222
|
grep_matcher,
|
|
@@ -5210,6 +5224,8 @@ def cmd_install_mcp(args):
|
|
|
5210
5224
|
edit_matcher,
|
|
5211
5225
|
write_matcher,
|
|
5212
5226
|
*extra_edit_matchers,
|
|
5227
|
+
shell_matcher,
|
|
5228
|
+
"run_shell_command",
|
|
5213
5229
|
]
|
|
5214
5230
|
desired_pre_hooks = [
|
|
5215
5231
|
{"matcher": m, "hooks": [{"type": "command", "command": hook_pretool_cmd}]}
|
|
@@ -5899,6 +5915,297 @@ def _creds_cmd_import(args, project_path: str) -> None:
|
|
|
5899
5915
|
"(use --overwrite to replace)")
|
|
5900
5916
|
|
|
5901
5917
|
|
|
5918
|
+
def cmd_access(args):
|
|
5919
|
+
"""Access Guard rule management — human-only mutation surface (spec §1)."""
|
|
5920
|
+
sub = getattr(args, "access_cmd", None)
|
|
5921
|
+
if not sub:
|
|
5922
|
+
print("Usage: c3 access {list,add,remove,check,mask} [args]")
|
|
5923
|
+
print(" c3 access mask {add,rm,status,activate,preview} [args]")
|
|
5924
|
+
return
|
|
5925
|
+
|
|
5926
|
+
project_path = getattr(args, "project_path", ".") or "."
|
|
5927
|
+
|
|
5928
|
+
if sub == "list":
|
|
5929
|
+
_access_cmd_list(args, project_path)
|
|
5930
|
+
elif sub == "add":
|
|
5931
|
+
_access_cmd_add(args, project_path)
|
|
5932
|
+
elif sub == "remove":
|
|
5933
|
+
_access_cmd_remove(args, project_path)
|
|
5934
|
+
elif sub == "check":
|
|
5935
|
+
_access_cmd_check(args, project_path)
|
|
5936
|
+
elif sub == "mask":
|
|
5937
|
+
_access_cmd_mask(args, project_path)
|
|
5938
|
+
else:
|
|
5939
|
+
print(f"Unknown access subcommand: {sub}")
|
|
5940
|
+
|
|
5941
|
+
|
|
5942
|
+
def _access_scope(args) -> str:
|
|
5943
|
+
return "global" if getattr(args, "use_global", False) else "project"
|
|
5944
|
+
|
|
5945
|
+
|
|
5946
|
+
def _access_audit(action: str, glob: str, kind: str, scope: str,
|
|
5947
|
+
project_path: str) -> None:
|
|
5948
|
+
"""Ledger + activity log for CLI rule mutations. Identifiers only; failure-safe."""
|
|
5949
|
+
try:
|
|
5950
|
+
from services.activity_log import ActivityLog
|
|
5951
|
+
ActivityLog(project_path).log("access_action", {
|
|
5952
|
+
"kind": "access", "action": action, "glob": glob,
|
|
5953
|
+
"rule_kind": kind, "scope": scope, "via": "cli",
|
|
5954
|
+
})
|
|
5955
|
+
except Exception:
|
|
5956
|
+
pass
|
|
5957
|
+
try:
|
|
5958
|
+
from services.edit_ledger import EditLedger
|
|
5959
|
+
EditLedger(project_path).log_edit(
|
|
5960
|
+
file=f"access://{glob}", change_type=f"access_{action}",
|
|
5961
|
+
summary=f"{action} {kind} rule '{glob}' ({scope}) via `c3 access`",
|
|
5962
|
+
tags=["access", action],
|
|
5963
|
+
detail={"kind": "access", "action": action, "glob": glob,
|
|
5964
|
+
"rule_kind": kind, "scope": scope},
|
|
5965
|
+
)
|
|
5966
|
+
except Exception:
|
|
5967
|
+
pass
|
|
5968
|
+
|
|
5969
|
+
|
|
5970
|
+
def _access_cmd_list(args, project_path: str) -> None:
|
|
5971
|
+
from services import access_guard
|
|
5972
|
+
|
|
5973
|
+
scopes = access_guard.list_rules(project_path)
|
|
5974
|
+
notes = {"builtin": "built-in, always on",
|
|
5975
|
+
"global": "~/.c3/config.json",
|
|
5976
|
+
"project": ".c3/config.json"}
|
|
5977
|
+
for scope in ("builtin", "global", "project"):
|
|
5978
|
+
sec = scopes.get(scope) or {}
|
|
5979
|
+
rules = [(k, g) for k in ("deny", "read_only") for g in sec.get(k, [])]
|
|
5980
|
+
masks = sec.get("mask") or []
|
|
5981
|
+
print(f"[{scope}] ({notes[scope]}) — {len(rules) + len(masks)} rule(s)")
|
|
5982
|
+
for kind, glob in rules:
|
|
5983
|
+
print(f" {kind:<10} {glob}")
|
|
5984
|
+
for entry in masks:
|
|
5985
|
+
params = entry.get("params") or {}
|
|
5986
|
+
detail = ", ".join(f"{k}={v}" for k, v in sorted(params.items()))
|
|
5987
|
+
print(f" {'mask':<10} {entry.get('glob')} -> "
|
|
5988
|
+
f"{entry.get('preset')}" + (f"({detail})" if detail else ""))
|
|
5989
|
+
if sec.get("corrupt"):
|
|
5990
|
+
print(" [warn] access section invalid — scope fails closed "
|
|
5991
|
+
"(deny-all); fix config.json 'access' by hand")
|
|
5992
|
+
print()
|
|
5993
|
+
from services import mask_activation
|
|
5994
|
+
summary = mask_activation.summary_line(project_path)
|
|
5995
|
+
if summary:
|
|
5996
|
+
print(summary)
|
|
5997
|
+
print()
|
|
5998
|
+
print(access_guard.COVERAGE_MATRIX)
|
|
5999
|
+
|
|
6000
|
+
|
|
6001
|
+
def _access_cmd_add(args, project_path: str) -> None:
|
|
6002
|
+
from services import access_guard
|
|
6003
|
+
|
|
6004
|
+
scope = _access_scope(args)
|
|
6005
|
+
try:
|
|
6006
|
+
result = access_guard.set_rule(args.glob, args.kind, scope, project_path)
|
|
6007
|
+
except ValueError as exc:
|
|
6008
|
+
print(f"[error] {exc}")
|
|
6009
|
+
return
|
|
6010
|
+
if result["added"]:
|
|
6011
|
+
_access_audit("add", result["glob"], args.kind, scope, project_path)
|
|
6012
|
+
print(f"[OK] Added {args.kind} rule '{result['glob']}' (scope={scope})")
|
|
6013
|
+
else:
|
|
6014
|
+
print(f"[=] Rule already present: '{result['glob']}' "
|
|
6015
|
+
f"({args.kind}, {scope})")
|
|
6016
|
+
|
|
6017
|
+
|
|
6018
|
+
def _access_cmd_remove(args, project_path: str) -> None:
|
|
6019
|
+
from services import access_guard
|
|
6020
|
+
|
|
6021
|
+
scope = _access_scope(args)
|
|
6022
|
+
try:
|
|
6023
|
+
result = access_guard.remove_rule(args.glob, args.kind, scope, project_path)
|
|
6024
|
+
except ValueError as exc:
|
|
6025
|
+
print(f"[error] {exc}")
|
|
6026
|
+
return
|
|
6027
|
+
if result["removed"]:
|
|
6028
|
+
_access_audit("remove", result["glob"], args.kind, scope, project_path)
|
|
6029
|
+
print(f"[OK] Removed {args.kind} rule '{result['glob']}' (scope={scope})")
|
|
6030
|
+
else:
|
|
6031
|
+
print(f"[error] no {args.kind} rule matching '{result['glob']}' "
|
|
6032
|
+
f"in {scope} scope")
|
|
6033
|
+
|
|
6034
|
+
|
|
6035
|
+
def _access_cmd_check(args, project_path: str) -> None:
|
|
6036
|
+
from services import access_guard
|
|
6037
|
+
|
|
6038
|
+
op = getattr(args, "op", "read") or "read"
|
|
6039
|
+
v = access_guard.verdict(args.target, op, project_path)
|
|
6040
|
+
if v.masked:
|
|
6041
|
+
rule = v.mask_rule
|
|
6042
|
+
print(f"[MASKED] {op} served as a transformed view: {args.target}")
|
|
6043
|
+
print(f" rule '{rule.glob}' ({rule.scope} scope) -> {rule.preset}")
|
|
6044
|
+
print(" Preview what the agent sees: "
|
|
6045
|
+
f"c3 access mask preview {args.target}")
|
|
6046
|
+
elif v.denial is None:
|
|
6047
|
+
print(f"[OK] {op} allowed: {args.target}")
|
|
6048
|
+
else:
|
|
6049
|
+
print(access_guard.refusal(v.denial, args.target, op))
|
|
6050
|
+
|
|
6051
|
+
|
|
6052
|
+
# ── mask subcommands ────────────────────────────────────────────────────────
|
|
6053
|
+
|
|
6054
|
+
def _parse_mask_params(raw: str, preset: str) -> dict:
|
|
6055
|
+
"""`count=20,strategy=first` / `columns=email,name` -> typed params."""
|
|
6056
|
+
from services import access_guard
|
|
6057
|
+
|
|
6058
|
+
schema = (access_guard.MASK_PRESETS.get(preset) or {}).get("params", {})
|
|
6059
|
+
params: dict = {}
|
|
6060
|
+
for chunk in (raw or "").split(","):
|
|
6061
|
+
chunk = chunk.strip()
|
|
6062
|
+
if not chunk:
|
|
6063
|
+
continue
|
|
6064
|
+
if "=" not in chunk:
|
|
6065
|
+
# bare value continues the previous list param (columns=a,b,c)
|
|
6066
|
+
last = next((k for k in reversed(list(params))
|
|
6067
|
+
if schema.get(k) is list), None)
|
|
6068
|
+
if last:
|
|
6069
|
+
params[last].append(chunk)
|
|
6070
|
+
continue
|
|
6071
|
+
raise ValueError(f"cannot parse param '{chunk}' — use key=value")
|
|
6072
|
+
key, value = (part.strip() for part in chunk.split("=", 1))
|
|
6073
|
+
expected = schema.get(key)
|
|
6074
|
+
if expected is int:
|
|
6075
|
+
params[key] = int(value)
|
|
6076
|
+
elif expected is list:
|
|
6077
|
+
params[key] = [value]
|
|
6078
|
+
else:
|
|
6079
|
+
params[key] = value
|
|
6080
|
+
return params
|
|
6081
|
+
|
|
6082
|
+
|
|
6083
|
+
def _access_cmd_mask_add(args, project_path: str) -> None:
|
|
6084
|
+
from services import access_guard, mask_activation
|
|
6085
|
+
|
|
6086
|
+
scope = _access_scope(args)
|
|
6087
|
+
try:
|
|
6088
|
+
params = _parse_mask_params(getattr(args, "params", "") or "",
|
|
6089
|
+
args.preset)
|
|
6090
|
+
result = access_guard.set_mask_rule(args.glob, args.preset, params,
|
|
6091
|
+
scope, project_path)
|
|
6092
|
+
except ValueError as exc:
|
|
6093
|
+
print(f"[error] {exc}")
|
|
6094
|
+
return
|
|
6095
|
+
_access_audit("mask-add", result["glob"], args.preset, scope, project_path)
|
|
6096
|
+
verb = "Replaced" if result["replaced"] else "Added"
|
|
6097
|
+
print(f"[OK] {verb} mask rule '{result['glob']}' -> {args.preset} "
|
|
6098
|
+
f"(scope={scope})")
|
|
6099
|
+
print()
|
|
6100
|
+
print(mask_activation.summary_line(project_path))
|
|
6101
|
+
print("Run `c3 access mask activate` to purge pre-mask derived artifacts.")
|
|
6102
|
+
|
|
6103
|
+
|
|
6104
|
+
def _access_cmd_mask_remove(args, project_path: str) -> None:
|
|
6105
|
+
from services import access_guard
|
|
6106
|
+
|
|
6107
|
+
scope = _access_scope(args)
|
|
6108
|
+
try:
|
|
6109
|
+
result = access_guard.remove_mask_rule(args.glob, scope, project_path)
|
|
6110
|
+
except ValueError as exc:
|
|
6111
|
+
print(f"[error] {exc}")
|
|
6112
|
+
return
|
|
6113
|
+
if result["removed"]:
|
|
6114
|
+
_access_audit("mask-remove", result["glob"], "mask", scope,
|
|
6115
|
+
project_path)
|
|
6116
|
+
print(f"[OK] Removed mask rule '{result['glob']}' (scope={scope})")
|
|
6117
|
+
else:
|
|
6118
|
+
print(f"[error] no mask rule matching '{result['glob']}' "
|
|
6119
|
+
f"in {scope} scope")
|
|
6120
|
+
|
|
6121
|
+
|
|
6122
|
+
def _access_cmd_mask_status(args, project_path: str) -> None:
|
|
6123
|
+
from services import mask_activation
|
|
6124
|
+
|
|
6125
|
+
st = mask_activation.status(project_path)
|
|
6126
|
+
print(f"rules : {st['rule_count']}")
|
|
6127
|
+
print(f"status : {st['status']}")
|
|
6128
|
+
print(f"stale : {st['stale']}")
|
|
6129
|
+
if st["corrupt_scopes"]:
|
|
6130
|
+
print(f"corrupt : {', '.join(st['corrupt_scopes'])}")
|
|
6131
|
+
report = st.get("last_report") or {}
|
|
6132
|
+
if report:
|
|
6133
|
+
print(f"last run : {report.get('views_built', 0)} view(s) built, "
|
|
6134
|
+
f"{len(report.get('failures') or [])} failure(s)")
|
|
6135
|
+
for failure in (report.get("failures") or [])[:10]:
|
|
6136
|
+
print(f" [fail] {failure['path']}: {failure['detail']}")
|
|
6137
|
+
print()
|
|
6138
|
+
print(mask_activation.summary_line(project_path) or "no mask rules")
|
|
6139
|
+
|
|
6140
|
+
|
|
6141
|
+
def _access_cmd_mask_activate(args, project_path: str) -> None:
|
|
6142
|
+
from services import mask_activation
|
|
6143
|
+
|
|
6144
|
+
print("Activating mask rules (purge -> build -> validate)...")
|
|
6145
|
+
report = mask_activation.activate(
|
|
6146
|
+
project_path, rebuild_index=bool(getattr(args, "reindex", False)))
|
|
6147
|
+
print(f" files matched : {report['files']}")
|
|
6148
|
+
print(f" views built : {report['views_built']}")
|
|
6149
|
+
print(f" cache entries wiped: {report['cache_entries_removed']}")
|
|
6150
|
+
print(f" index dropped : {report['index_dropped']}")
|
|
6151
|
+
print(f" file memory dropped: {report['file_memory_dropped']}")
|
|
6152
|
+
facts = report.get("facts") or {}
|
|
6153
|
+
print(f" facts purged : {facts.get('purged', 0)} "
|
|
6154
|
+
f"(+{facts.get('unknown_purged', 0)} unknown-provenance)")
|
|
6155
|
+
for failure in report.get("failures") or []:
|
|
6156
|
+
print(f" [fail] {failure['path']}: {failure['detail']}")
|
|
6157
|
+
_access_audit("mask-activate", f"{report['files']} file(s)", "mask",
|
|
6158
|
+
"project", project_path)
|
|
6159
|
+
print()
|
|
6160
|
+
print(mask_activation.summary_line(project_path))
|
|
6161
|
+
|
|
6162
|
+
|
|
6163
|
+
def _access_cmd_mask_preview(args, project_path: str) -> None:
|
|
6164
|
+
"""Show exactly what the agent will see. Human surface only."""
|
|
6165
|
+
from pathlib import Path as _Path
|
|
6166
|
+
|
|
6167
|
+
from services import access_guard, mask_mirror
|
|
6168
|
+
|
|
6169
|
+
target = _Path(args.target)
|
|
6170
|
+
if not target.is_absolute():
|
|
6171
|
+
target = _Path(project_path) / args.target
|
|
6172
|
+
v = access_guard.verdict(str(target), "read", project_path)
|
|
6173
|
+
if v.denial:
|
|
6174
|
+
print(access_guard.refusal(v.denial, str(target), "read"))
|
|
6175
|
+
return
|
|
6176
|
+
if not v.masked:
|
|
6177
|
+
print(f"[=] Not masked: {args.target} — the agent sees the real file.")
|
|
6178
|
+
return
|
|
6179
|
+
try:
|
|
6180
|
+
view = mask_mirror.render_for_path(target, project_path)
|
|
6181
|
+
except mask_mirror.MaskUnavailable as exc:
|
|
6182
|
+
print(f"[error] {exc.message}")
|
|
6183
|
+
return
|
|
6184
|
+
print(f"rule : '{v.mask_rule.glob}' ({v.mask_rule.scope} scope)")
|
|
6185
|
+
print(f"preset : {v.mask_rule.preset} {v.mask_rule.params_dict or ''}")
|
|
6186
|
+
print(f"stats : {view.stats}")
|
|
6187
|
+
print("-" * 70)
|
|
6188
|
+
print(view.with_header(args.target))
|
|
6189
|
+
|
|
6190
|
+
|
|
6191
|
+
def _access_cmd_mask(args, project_path: str) -> None:
|
|
6192
|
+
sub = getattr(args, "mask_cmd", None) or "status"
|
|
6193
|
+
handlers = {
|
|
6194
|
+
"add": _access_cmd_mask_add,
|
|
6195
|
+
"rm": _access_cmd_mask_remove,
|
|
6196
|
+
"remove": _access_cmd_mask_remove,
|
|
6197
|
+
"status": _access_cmd_mask_status,
|
|
6198
|
+
"activate": _access_cmd_mask_activate,
|
|
6199
|
+
"preview": _access_cmd_mask_preview,
|
|
6200
|
+
}
|
|
6201
|
+
handler = handlers.get(sub)
|
|
6202
|
+
if handler is None:
|
|
6203
|
+
print(f"[error] unknown mask subcommand '{sub}' — expected one of: "
|
|
6204
|
+
f"{', '.join(sorted(handlers))}")
|
|
6205
|
+
return
|
|
6206
|
+
handler(args, project_path)
|
|
6207
|
+
|
|
6208
|
+
|
|
5902
6209
|
def cmd_jira(args):
|
|
5903
6210
|
"""Jira Cloud / Data Center credential + workspace management."""
|
|
5904
6211
|
sub = getattr(args, "jira_cmd", None)
|
|
@@ -7199,6 +7506,7 @@ def main():
|
|
|
7199
7506
|
"bitbucket": cmd_bitbucket,
|
|
7200
7507
|
"jira": cmd_jira,
|
|
7201
7508
|
"creds": cmd_creds,
|
|
7509
|
+
"access": cmd_access,
|
|
7202
7510
|
"oracle": cmd_oracle,
|
|
7203
7511
|
"upgrade": cmd_upgrade,
|
|
7204
7512
|
}
|
|
@@ -447,6 +447,84 @@ def build_parser(version: str, parse_cli_ide_arg):
|
|
|
447
447
|
cr_import.add_argument("--overwrite", action="store_true", help="Replace entries already registered in the target scope")
|
|
448
448
|
cr_import.add_argument("--path", dest="project_path", default=".", help="Project directory (default: current)")
|
|
449
449
|
|
|
450
|
+
# ── Access Guard (v2.62.0) ──────────────────────────────────────────
|
|
451
|
+
# Human-only mutation surface (frozen spec docs/access-guard.md §1):
|
|
452
|
+
# rule changes happen here or in the UI tab, never via an agent tool.
|
|
453
|
+
p_access = subparsers.add_parser(
|
|
454
|
+
"access",
|
|
455
|
+
help="Access Guard — path deny/read-only rules the agent must respect",
|
|
456
|
+
)
|
|
457
|
+
access_subs = p_access.add_subparsers(dest="access_cmd")
|
|
458
|
+
|
|
459
|
+
ac_list = access_subs.add_parser(
|
|
460
|
+
"list", help="Show rules per scope (builtin + global + project) and coverage"
|
|
461
|
+
)
|
|
462
|
+
ac_list.add_argument("--path", dest="project_path", default=".", help="Project directory (default: current)")
|
|
463
|
+
|
|
464
|
+
ac_add = access_subs.add_parser("add", help="Add a rule to the project (or --global) scope")
|
|
465
|
+
ac_add.add_argument("glob", help="POSIX glob (** crosses directories), e.g. 'secrets/**' or '*.pem'")
|
|
466
|
+
ac_add.add_argument("--kind", choices=["deny", "read_only"], required=True,
|
|
467
|
+
help="deny = no read/write/enumerate; read_only = no write")
|
|
468
|
+
ac_add.add_argument("--global", dest="use_global", action="store_true",
|
|
469
|
+
help="Store in the global scope (~/.c3) so every C3 project enforces it")
|
|
470
|
+
ac_add.add_argument("--path", dest="project_path", default=".", help="Project directory (default: current)")
|
|
471
|
+
|
|
472
|
+
ac_remove = access_subs.add_parser("remove", help="Remove a rule from the project (or --global) scope")
|
|
473
|
+
ac_remove.add_argument("glob", help="The stored glob to remove (case-insensitive match)")
|
|
474
|
+
ac_remove.add_argument("--kind", choices=["deny", "read_only"], required=True,
|
|
475
|
+
help="Which rule list the glob lives in")
|
|
476
|
+
ac_remove.add_argument("--global", dest="use_global", action="store_true",
|
|
477
|
+
help="Remove from the global scope (~/.c3)")
|
|
478
|
+
ac_remove.add_argument("--path", dest="project_path", default=".", help="Project directory (default: current)")
|
|
479
|
+
|
|
480
|
+
ac_check = access_subs.add_parser("check", help="Test a path: verdict + matched rule + refusal string")
|
|
481
|
+
ac_check.add_argument("target", help="Path to test (absolute or project-relative)")
|
|
482
|
+
ac_check.add_argument("--op", choices=["read", "write"], default="read",
|
|
483
|
+
help="Operation to evaluate (default: read)")
|
|
484
|
+
ac_check.add_argument("--path", dest="project_path", default=".", help="Project directory (default: current)")
|
|
485
|
+
|
|
486
|
+
# ── Mask Guard (v2.63.0, docs/mask-guard.md) ────────────────────────
|
|
487
|
+
# Masking exposes a path but transforms what the agent sees. Rules are
|
|
488
|
+
# human-only, like the rest of Access Guard.
|
|
489
|
+
ac_mask = access_subs.add_parser(
|
|
490
|
+
"mask", help="Mask Guard — expose a path but transform what the agent sees")
|
|
491
|
+
mask_subs = ac_mask.add_subparsers(dest="mask_cmd")
|
|
492
|
+
|
|
493
|
+
am_add = mask_subs.add_parser("add", help="Add or replace a mask rule")
|
|
494
|
+
am_add.add_argument("glob", help="POSIX glob, e.g. 'data/**' or '*.csv'")
|
|
495
|
+
am_add.add_argument("--preset", required=True,
|
|
496
|
+
choices=["redact_secrets", "redact_columns",
|
|
497
|
+
"sample_rows", "signatures_only"],
|
|
498
|
+
help="Deterministic transform applied to matching files")
|
|
499
|
+
am_add.add_argument("--params", default="",
|
|
500
|
+
help="Preset params, e.g. 'count=20,strategy=first' "
|
|
501
|
+
"or 'columns=email,name'")
|
|
502
|
+
am_add.add_argument("--global", dest="use_global", action="store_true",
|
|
503
|
+
help="Store in the global scope (~/.c3)")
|
|
504
|
+
am_add.add_argument("--path", dest="project_path", default=".", help="Project directory (default: current)")
|
|
505
|
+
|
|
506
|
+
am_rm = mask_subs.add_parser("rm", help="Remove a mask rule")
|
|
507
|
+
am_rm.add_argument("glob", help="The stored glob to remove")
|
|
508
|
+
am_rm.add_argument("--global", dest="use_global", action="store_true",
|
|
509
|
+
help="Remove from the global scope (~/.c3)")
|
|
510
|
+
am_rm.add_argument("--path", dest="project_path", default=".", help="Project directory (default: current)")
|
|
511
|
+
|
|
512
|
+
am_status = mask_subs.add_parser(
|
|
513
|
+
"status", help="Activation state — whether masking is actually in effect")
|
|
514
|
+
am_status.add_argument("--path", dest="project_path", default=".", help="Project directory (default: current)")
|
|
515
|
+
|
|
516
|
+
am_act = mask_subs.add_parser(
|
|
517
|
+
"activate",
|
|
518
|
+
help="Purge pre-mask derived artifacts, then build + validate views")
|
|
519
|
+
am_act.add_argument("--reindex", action="store_true",
|
|
520
|
+
help="Also rebuild the code index in the same pass")
|
|
521
|
+
am_act.add_argument("--path", dest="project_path", default=".", help="Project directory (default: current)")
|
|
522
|
+
|
|
523
|
+
am_prev = mask_subs.add_parser(
|
|
524
|
+
"preview", help="Show exactly what the agent sees for one path")
|
|
525
|
+
am_prev.add_argument("target", help="Path to preview (absolute or project-relative)")
|
|
526
|
+
am_prev.add_argument("--path", dest="project_path", default=".", help="Project directory (default: current)")
|
|
527
|
+
|
|
450
528
|
# ── Oracle Discovery API (v2.32.0) ──────────────────────────────────
|
|
451
529
|
p_oracle = subparsers.add_parser(
|
|
452
530
|
"oracle",
|