code-context-control 2.85.0__tar.gz → 2.86.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.85.0/code_context_control.egg-info → code_context_control-2.86.0}/PKG-INFO +3 -2
- {code_context_control-2.85.0 → code_context_control-2.86.0}/README.md +2 -1
- {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/c3.py +19 -1
- {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/hook_access_guard.py +25 -3
- {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/hub_server.py +14 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/mcp_server.py +3 -1
- {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/server.py +14 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/tools/shell.py +56 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/tools/tasks.py +22 -1
- {code_context_control-2.85.0 → code_context_control-2.86.0/code_context_control.egg-info}/PKG-INFO +3 -2
- {code_context_control-2.85.0 → code_context_control-2.86.0}/oracle/services/mobile_api.py +14 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/pyproject.toml +1 -1
- {code_context_control-2.85.0 → code_context_control-2.86.0}/services/access_guard.py +27 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/services/scanner.py +35 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/services/task_store.py +63 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_access_guard.py +72 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_c3_shell.py +101 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_hook_access_guard.py +30 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_init_scan.py +76 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_pm_api.py +25 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_task_store.py +45 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_task_tool.py +13 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/LICENSE +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/__init__.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/_hook_utils.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/commands/__init__.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/commands/common.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/commands/parser.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/docs.html +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/edits.html +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/guide/access.html +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/guide/bitbucket.html +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/guide/credentials.html +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/guide/getting-started.html +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/guide/index.html +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/guide/masking.html +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/guide/oracle.html +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/guide/shared.css +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/guide/tools.html +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/guide/workflow.html +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/hook_artifact.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/hook_auto_snapshot.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/hook_c3_signal.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/hook_c3read.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/hook_dispatch.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/hook_edit_ledger.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/hook_edit_unlock.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/hook_filter.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/hook_ghost_files.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/hook_pretool_enforce.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/hook_prompt_recall.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/hook_read.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/hook_session_stats.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/hook_terse_advisor.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/hub_ui/app.js +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/hub_ui/components/add_project.js +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/hub_ui/components/config_editor.js +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/hub_ui/components/drill_artifacts.js +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/hub_ui/components/drill_health.js +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/hub_ui/components/drill_panel.js +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/hub_ui/components/drill_subprojects.js +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/hub_ui/components/drill_tasks.js +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/hub_ui/components/drill_views.js +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/hub_ui/components/global_search.js +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/hub_ui/components/hub_ci.js +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/hub_ui/components/hub_credentials.js +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/hub_ui/components/hub_enforcement.js +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/hub_ui/components/hub_locks.js +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/hub_ui/components/mcp_manager.js +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/hub_ui/components/modals.js +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/hub_ui/components/project_card.js +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/hub_ui/components/project_tree.js +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/hub_ui/components/session_drawer.js +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/hub_ui/components/settings_modal.js +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/hub_ui/components/sidebar.js +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/hub_ui/components/summary_bar.js +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/hub_ui/components/task_board.js +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/hub_ui/components/toasts.js +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/hub_ui/components/topbar.js +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/hub_ui/state.js +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/hub_ui.html +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/mcp_proxy.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/progress.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/tools/__init__.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/tools/_grants.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/tools/_helpers.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/tools/agent.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/tools/artifacts.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/tools/bitbucket.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/tools/ci.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/tools/compress.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/tools/credentials.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/tools/delegate.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/tools/edit.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/tools/edit_verify.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/tools/edits.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/tools/federate.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/tools/filter.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/tools/impact.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/tools/jira.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/tools/locks.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/tools/memory.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/tools/override.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/tools/project.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/tools/read.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/tools/search.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/tools/session.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/tools/status.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/tools/validate.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/ui/api.js +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/ui/app.js +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/ui/components/access.js +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/ui/components/bitbucket.js +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/ui/components/chat.js +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/ui/components/credentials.js +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/ui/components/dashboard.js +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/ui/components/edits.js +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/ui/components/enforcement.js +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/ui/components/instructions.js +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/ui/components/jira.js +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/ui/components/memory.js +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/ui/components/sessions.js +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/ui/components/settings.js +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/ui/components/sidebar.js +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/ui/components/tasks.js +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/ui/icons.js +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/ui/pm_shared.js +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/ui/shared.js +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/ui/theme.js +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/ui.html +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/ui_legacy.html +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/ui_nano.html +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/code_context_control.egg-info/SOURCES.txt +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/code_context_control.egg-info/dependency_links.txt +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/code_context_control.egg-info/entry_points.txt +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/code_context_control.egg-info/requires.txt +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/code_context_control.egg-info/top_level.txt +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/core/__init__.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/core/config.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/core/ide.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/core/mcp_toml.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/core/web_security.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/oracle/__init__.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/oracle/config.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/oracle/mcp_oracle.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/oracle/oracle_server.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/oracle/oracle_ui.html +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/oracle/services/__init__.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/oracle/services/activity_reporter.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/oracle/services/api_auth.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/oracle/services/c3_bridge.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/oracle/services/chat_engine.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/oracle/services/chat_poll.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/oracle/services/chat_store.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/oracle/services/cross_memory.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/oracle/services/discovery_audit.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/oracle/services/federated_graph.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/oracle/services/health_checker.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/oracle/services/insight_engine.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/oracle/services/local_session.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/oracle/services/memory_reader.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/oracle/services/memory_writer.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/oracle/services/project_scanner.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/oracle/services/review_agent.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/oracle/services/tool_executor.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/oracle/services/tool_registry.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/oracle/ui/activity.js +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/oracle/ui/agents.js +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/oracle/ui/app.js +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/oracle/ui/busy.js +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/oracle/ui/chat/conversations.js +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/oracle/ui/chat/input.js +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/oracle/ui/chat/markdown.js +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/oracle/ui/chat/send.js +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/oracle/ui/chat/stream_renderer.js +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/oracle/ui/chat/toolbar.js +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/oracle/ui/core.js +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/oracle/ui/crossgraph.js +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/oracle/ui/header.js +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/oracle/ui/insights.js +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/oracle/ui/projects.js +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/oracle/ui/qrcode.js +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/oracle/ui/settings.js +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/oracle/ui/suggestions.js +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/oracle/ui/theme_tabs.js +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/services/__init__.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/services/access_telemetry.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/services/activity_log.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/services/agent_base.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/services/agent_locks.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/services/agents.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/services/artifact_defs.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/services/artifact_store.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/services/auto_memory.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/services/bench/__init__.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/services/bench/external/__init__.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/services/bench/external/aider_polyglot.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/services/bench/external/swe_bench.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/services/benchmark_dashboard.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/services/bitbucket_client.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/services/bitbucket_credentials.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/services/ci_act.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/services/ci_cache.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/services/ci_expr.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/services/ci_failures.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/services/ci_github.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/services/ci_impact.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/services/ci_intel.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/services/ci_runner.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/services/ci_workflow.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/services/circuit_breaker.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/services/claude_md.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/services/compressor.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/services/context_snapshot.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/services/conversation_store.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/services/credential_store.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/services/doc_index.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/services/e2e_benchmark.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/services/e2e_evaluator.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/services/e2e_tasks.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/services/edit_ledger.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/services/embedding_index.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/services/enforcement_policy.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/services/error_reporting.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/services/file_memory.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/services/git_context.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/services/hub_service.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/services/indexer.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/services/jira_client.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/services/jira_cloud.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/services/jira_credentials.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/services/jira_data_center.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/services/jira_links.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/services/mask_activation.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/services/mask_mirror.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/services/mask_presets.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/services/memory.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/services/memory_consolidator.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/services/memory_distiller.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/services/memory_graph.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/services/memory_grounder.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/services/memory_queue.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/services/memory_scorer.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/services/metrics.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/services/notifications.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/services/ollama_bridge.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/services/ollama_client.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/services/ollama_credentials.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/services/output_filter.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/services/override_grants.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/services/override_policy.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/services/override_requests.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/services/override_wake.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/services/parser.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/services/project_manager.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/services/project_runtime.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/services/protocol.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/services/proxy_state.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/services/repo_map.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/services/retention.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/services/retrieval_broker.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/services/router.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/services/runtime.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/services/session_benchmark.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/services/session_manager.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/services/session_preloader.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/services/subprojects.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/services/telemetry.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/services/text_index.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/services/time_tracker.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/services/tool_classifier.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/services/transcript_index.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/services/validation_cache.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/services/vector_store.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/services/watcher.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/services/win_subprocess.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/setup.cfg +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_access_builtin_optout.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_access_guard_meta.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_access_guard_shell_project.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_access_guard_surfaces.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_access_guard_wiring.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_activity_reporter.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_agent_locks.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_aider_polyglot.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_antigravity_transition.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_artifact_store.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_artifact_tool.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_bitbucket_cli_smoke.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_bitbucket_client.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_bitbucket_config_fallback.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_bitbucket_credentials.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_bitbucket_tool.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_c3_bridge_project_artifacts.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_chat_poll.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_ci_act.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_ci_cache.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_ci_expr.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_ci_impact.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_ci_intel.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_ci_runner.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_ci_workflow.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_circuit_breaker.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_claude_md_merge.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_cli_smoke.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_compressor_large_file.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_credential_store.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_credentials_routes.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_credentials_tool.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_creds_cli_smoke.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_delegate_cascade.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_delegate_version_probe.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_e2e_benchmark.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_edit_ledger_deadline.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_edit_ledger_hook.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_edit_locking.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_edit_normalization.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_edit_verify.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_embedding_index_deadlock.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_enforcement_flip.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_enforcement_policy.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_enforcement_routes.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_federated_graph.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_filter_backoff.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_ghost_files.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_ghost_generation.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_git_branch_awareness.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_hook_codex_compat.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_hook_dispatch.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_hook_pretool_enforce.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_hook_prompt_recall.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_hook_smoke.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_hook_state.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_hook_utf8_stdio.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_hub_credentials_route.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_hub_credentials_routes_write.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_hub_enforcement_routes.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_hub_inspect_api.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_hub_locks_routes.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_hub_server_smoke.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_hub_subproject_links.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_ide_workflow_adaptation.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_install_mcp_entrypoint.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_jira_cli_smoke.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_jira_client.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_jira_config_fallback.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_jira_credentials.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_jira_links.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_jira_routes.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_jira_tool.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_lazy_store_init.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_mask_guard.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_mask_routes.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_mask_surfaces.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_mcp_host_guard.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_mcp_memory_timeout.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_mcp_server_smoke.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_mcp_toml.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_memory_distiller.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_memory_graph_api.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_memory_queue.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_memory_system.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_mobile_api.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_mobile_extras.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_mobile_override_routes.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_mobile_security_api.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_no_stale_model_pins.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_notification_dedup.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_notification_discipline.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_ollama_credentials.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_oracle_api_auth.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_oracle_apikey_api.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_oracle_c3_bridge.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_oracle_chat_engine.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_oracle_chat_store.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_oracle_discovery_api.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_oracle_discovery_audit.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_oracle_local_auth.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_oracle_ollama_bridge.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_oracle_scanner_cache.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_oracle_security_fixes.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_oracle_session_bootstrap.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_oracle_subproject_awareness.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_oracle_ui_bundle.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_output_filter.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_override_grants.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_override_grants_mcp.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_override_requests.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_override_wake.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_permissions.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_project_manager.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_project_manager_merge.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_project_tool.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_read_coercion.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_read_edit_parity.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_related_facts.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_repo_map.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_response_boilerplate.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_retention.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_review_digest.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_service_durability.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_session_benchmark.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_session_budget.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_shell_creds.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_shell_robustness.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_subproject_exclusion.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_subproject_federation.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_subprojects.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_swe_bench.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_time_tracker.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_token_telemetry.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_tool_registry.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_upgrade_and_version.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_validate.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_vault_write_guard.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_version_sync.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_web_security.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_windows_reliability.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tui/__init__.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tui/backend.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tui/main.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tui/screens/__init__.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tui/screens/benchmark_view.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tui/screens/claudemd_view.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tui/screens/compress_view.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tui/screens/index_view.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tui/screens/init_view.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tui/screens/mcp_view.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tui/screens/optimize_view.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tui/screens/pipe_view.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tui/screens/projects_view.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tui/screens/search_view.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tui/screens/session_view.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tui/screens/stats.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tui/screens/ui_view.py +0 -0
- {code_context_control-2.85.0 → code_context_control-2.86.0}/tui/theme.tcss +0 -0
{code_context_control-2.85.0/code_context_control.egg-info → code_context_control-2.86.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.86.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
|
|
@@ -178,7 +178,7 @@ Twelve tabs. The dashboard above shows token savings, indexed files, the live se
|
|
|
178
178
|
<img src="https://raw.githubusercontent.com/drknowhow/code-context-control/main/docs/screenshots/2026-07/ui_tasks.png" alt="C3 Tasks" width="900">
|
|
179
179
|
</p>
|
|
180
180
|
|
|
181
|
-
**Tasks** (v2.45.0, extended v2.53.0) is a durable per-project tracker — dependencies and subtasks, milestones, decision notes, full event history, health reports, and both automatic and manual time tracking. It rolls up into the Hub's cross-project board.
|
|
181
|
+
**Tasks** (v2.45.0, extended v2.53.0) is a durable per-project tracker — dependencies and subtasks, milestones, decision notes, full event history, health reports, and both automatic and manual time tracking. It rolls up into the Hub's cross-project board. Shipped milestones can be **completed** (v2.86.0) — they leave the board while their tasks keep the milestone link, unlike archiving, which detaches them.
|
|
182
182
|
|
|
183
183
|
**Instructions** keeps your agent-facing docs in sync. C3-generated content sits inside a `<!-- C3:BEGIN … -->` block; anything you write outside it is preserved. Since v2.60.0 generated docs point at `.c3/MAP.md` — a machine-owned, byte-stable repo map C3 refreshes automatically — instead of embedding a tree that goes stale. `AGENTS.md` serves both Codex and Antigravity; `GEMINI.md` is read if present but no longer generated (the Gemini CLI profile was removed in v2.52).
|
|
184
184
|
|
|
@@ -243,6 +243,7 @@ c3 access mask activate # purge pre-mask artifacts, buil
|
|
|
243
243
|
- **`deny` means deny-enumerate too** — denied paths never appear in search results, maps, or the vector index.
|
|
244
244
|
- **Masked means read-only, always.** Cropped rows have no inverse, so an edit in transformed coordinates would corrupt the one file you protected.
|
|
245
245
|
- **Four deterministic presets, no LLM in the read path:** `redact_secrets`, `redact_columns` (salted one-way pseudonyms — joins survive, no reverse dictionary), `sample_rows`, `signatures_only`.
|
|
246
|
+
- **Sensible defaults out of the box** (v2.86.0). A fresh install seeds `*.pem`, `id_rsa*`, and `*.key` as deny rules in global scope — visible in `c3 access list` and removable like any rule you wrote yourself. Delete one and it stays deleted.
|
|
246
247
|
- **Rule changes are human-only** (UI tab or CLI) and ledger-logged. Agents have no mutation surface.
|
|
247
248
|
- **Built-ins can be switched off when you need to** (v2.65.0). `**/.env*`, `**/.c3/**`, `**/.claude/settings*.json` and `**/.git/**` yield to `c3 access builtin disable <glob>`, which makes you retype the glob first. It takes **two keys** — a config entry *and* a keyring attestation — so an agent that manages to write `config.json` still cannot grant itself write access to your settings. The credential vault stays absolute.
|
|
248
249
|
- **Honest coverage.** This guards *cooperative* agents against mistakes and prompt injection. It is not a sandbox — a raw shell outside C3's tools still sees the real bytes.
|
|
@@ -115,7 +115,7 @@ Twelve tabs. The dashboard above shows token savings, indexed files, the live se
|
|
|
115
115
|
<img src="https://raw.githubusercontent.com/drknowhow/code-context-control/main/docs/screenshots/2026-07/ui_tasks.png" alt="C3 Tasks" width="900">
|
|
116
116
|
</p>
|
|
117
117
|
|
|
118
|
-
**Tasks** (v2.45.0, extended v2.53.0) is a durable per-project tracker — dependencies and subtasks, milestones, decision notes, full event history, health reports, and both automatic and manual time tracking. It rolls up into the Hub's cross-project board.
|
|
118
|
+
**Tasks** (v2.45.0, extended v2.53.0) is a durable per-project tracker — dependencies and subtasks, milestones, decision notes, full event history, health reports, and both automatic and manual time tracking. It rolls up into the Hub's cross-project board. Shipped milestones can be **completed** (v2.86.0) — they leave the board while their tasks keep the milestone link, unlike archiving, which detaches them.
|
|
119
119
|
|
|
120
120
|
**Instructions** keeps your agent-facing docs in sync. C3-generated content sits inside a `<!-- C3:BEGIN … -->` block; anything you write outside it is preserved. Since v2.60.0 generated docs point at `.c3/MAP.md` — a machine-owned, byte-stable repo map C3 refreshes automatically — instead of embedding a tree that goes stale. `AGENTS.md` serves both Codex and Antigravity; `GEMINI.md` is read if present but no longer generated (the Gemini CLI profile was removed in v2.52).
|
|
121
121
|
|
|
@@ -180,6 +180,7 @@ c3 access mask activate # purge pre-mask artifacts, buil
|
|
|
180
180
|
- **`deny` means deny-enumerate too** — denied paths never appear in search results, maps, or the vector index.
|
|
181
181
|
- **Masked means read-only, always.** Cropped rows have no inverse, so an edit in transformed coordinates would corrupt the one file you protected.
|
|
182
182
|
- **Four deterministic presets, no LLM in the read path:** `redact_secrets`, `redact_columns` (salted one-way pseudonyms — joins survive, no reverse dictionary), `sample_rows`, `signatures_only`.
|
|
183
|
+
- **Sensible defaults out of the box** (v2.86.0). A fresh install seeds `*.pem`, `id_rsa*`, and `*.key` as deny rules in global scope — visible in `c3 access list` and removable like any rule you wrote yourself. Delete one and it stays deleted.
|
|
183
184
|
- **Rule changes are human-only** (UI tab or CLI) and ledger-logged. Agents have no mutation surface.
|
|
184
185
|
- **Built-ins can be switched off when you need to** (v2.65.0). `**/.env*`, `**/.c3/**`, `**/.claude/settings*.json` and `**/.git/**` yield to `c3 access builtin disable <glob>`, which makes you retype the glob first. It takes **two keys** — a config entry *and* a keyring attestation — so an agent that manages to write `config.json` still cannot grant itself write access to your settings. The credential vault stays absolute.
|
|
185
186
|
- **Honest coverage.** This guards *cooperative* agents against mistakes and prompt injection. It is not a sandbox — a raw shell outside C3's tools still sees the real bytes.
|
|
@@ -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.86.0"
|
|
96
96
|
|
|
97
97
|
|
|
98
98
|
def _compress_file_cli(compressor, path, mode="smart", **kw):
|
|
@@ -5535,6 +5535,14 @@ def cmd_install_mcp(args):
|
|
|
5535
5535
|
except Exception as e:
|
|
5536
5536
|
print(f"Warning: Could not update global CLAUDE.md: {e}")
|
|
5537
5537
|
|
|
5538
|
+
# ── Default Access Guard rules (first run only) ─────────────
|
|
5539
|
+
from services import access_guard
|
|
5540
|
+
seeded = access_guard.seed_default_global_rules()
|
|
5541
|
+
if seeded.get("seeded"):
|
|
5542
|
+
rules = ", ".join(seeded["rules"])
|
|
5543
|
+
print(f"Seeded default Access Guard deny rules into global scope: {rules}")
|
|
5544
|
+
print(" (remove with: c3 access remove <glob> --kind deny --global)")
|
|
5545
|
+
|
|
5538
5546
|
# ── Install /terse skill for supported IDEs ──────────────────
|
|
5539
5547
|
if profile.name in ("claude-code", "codex"):
|
|
5540
5548
|
try:
|
|
@@ -6603,6 +6611,16 @@ def _override_audit(grant: dict, project_path: str) -> None:
|
|
|
6603
6611
|
|
|
6604
6612
|
def cmd_access(args):
|
|
6605
6613
|
"""Access Guard rule management — human-only mutation surface (spec §1)."""
|
|
6614
|
+
from services import access_guard
|
|
6615
|
+
|
|
6616
|
+
# First `c3 access` touch seeds the removable defaults (spec §1). A
|
|
6617
|
+
# no-op forever after: any existing access section, even an emptied
|
|
6618
|
+
# one, means the user has taken over the scope.
|
|
6619
|
+
seeded = access_guard.seed_default_global_rules()
|
|
6620
|
+
if seeded.get("seeded"):
|
|
6621
|
+
print(f"[seeded] default global deny rules: {', '.join(seeded['rules'])}")
|
|
6622
|
+
print(" Remove any of them: c3 access remove <glob> --kind deny --global\n")
|
|
6623
|
+
|
|
6606
6624
|
sub = getattr(args, "access_cmd", None)
|
|
6607
6625
|
if not sub:
|
|
6608
6626
|
print("Usage: c3 access {list,add,remove,check,stats,mask,builtin} [args]")
|
|
@@ -41,7 +41,24 @@ _MAX_TOKENS = 200
|
|
|
41
41
|
# "NTFS alternate data stream". The ADS check stays strict for real path
|
|
42
42
|
# arguments (_WRITE_TOOLS/_READ_TOOLS); here it only produced false denies on
|
|
43
43
|
# commit messages, curl, and gh (#50).
|
|
44
|
-
|
|
44
|
+
#
|
|
45
|
+
# UNANCHORED, and that is the fix rather than an oversight. `^…://` only ever
|
|
46
|
+
# recognised a token that BEGINS with a scheme, which is the same
|
|
47
|
+
# whitelist-a-shape mistake #50 made and this module's own header calls out —
|
|
48
|
+
# and the `_SYNTAX_CHARS` generalisation does not cover the gap, because a
|
|
49
|
+
# token can carry a URL and no syntax at all. Observed 2026-08-11: the single
|
|
50
|
+
# argument of
|
|
51
|
+
# printf '\n---\n\nhttps://claude.ai/code/session_01Hs28…\n' >> body.md
|
|
52
|
+
# strips to `\n---\n\nhttps://claude.ai/…`, which has a separator (`\` and
|
|
53
|
+
# `/`), no syntax characters, no `::`, and no leading scheme. It reached
|
|
54
|
+
# ag.check, canonicalised to a residual colon, and hard-denied a command whose
|
|
55
|
+
# only file argument was an ordinary markdown path. Third logged instance of
|
|
56
|
+
# this class in five days (two on 2026-08-07 were Windows paths inside Python
|
|
57
|
+
# string literals).
|
|
58
|
+
#
|
|
59
|
+
# A token containing `://` anywhere is a network literal, not an NTFS stream:
|
|
60
|
+
# a real stream is `file:name:$TYPE`, and no spelling of it contains `//`.
|
|
61
|
+
_SCHEME_RE = re.compile(r"[a-z][a-z0-9+.\-]*://", re.IGNORECASE)
|
|
45
62
|
# IPv6 literal or CIDR: >=2 colons, hex groups only, optional [] and /prefix.
|
|
46
63
|
# 'C:/x/f.txt:stream' has one colon and non-hex parts, so it never matches.
|
|
47
64
|
_IPV6_RE = re.compile(
|
|
@@ -104,8 +121,13 @@ _CD_RE = re.compile(
|
|
|
104
121
|
|
|
105
122
|
|
|
106
123
|
def _is_network_token(tok: str) -> bool:
|
|
107
|
-
"""True for URLs and IPv6 literals/CIDRs — never for an ADS spelling.
|
|
108
|
-
|
|
124
|
+
"""True for URLs and IPv6 literals/CIDRs — never for an ADS spelling.
|
|
125
|
+
|
|
126
|
+
``search`` for the scheme (a URL anywhere in the token disqualifies it as
|
|
127
|
+
a path), ``match`` for IPv6 — that pattern is a whole-token shape and
|
|
128
|
+
anchoring is what keeps `C:/x/f.txt:stream` from matching it.
|
|
129
|
+
"""
|
|
130
|
+
return bool(_SCHEME_RE.search(tok) or _IPV6_RE.match(tok))
|
|
109
131
|
|
|
110
132
|
|
|
111
133
|
def _is_scope_token(tok: str) -> bool:
|
|
@@ -2740,6 +2740,20 @@ def api_pm_milestone():
|
|
|
2740
2740
|
return jsonify({"error": "id is required"}), 400
|
|
2741
2741
|
|
|
2742
2742
|
if request.method == "PUT":
|
|
2743
|
+
# {complete: true} / {reopen: true} switch lifecycle; tasks keep
|
|
2744
|
+
# their milestone link (unlike DELETE = archive + detach).
|
|
2745
|
+
if data.get("complete"):
|
|
2746
|
+
res = store.complete_milestone(ms_id)
|
|
2747
|
+
if "error" in res:
|
|
2748
|
+
return jsonify(res), 400
|
|
2749
|
+
_pm_audit(resolved, "milestone", "complete", res["id"])
|
|
2750
|
+
return jsonify({"completed": True, "milestone": res})
|
|
2751
|
+
if data.get("reopen"):
|
|
2752
|
+
res = store.reopen_milestone(ms_id)
|
|
2753
|
+
if "error" in res:
|
|
2754
|
+
return jsonify(res), 400
|
|
2755
|
+
_pm_audit(resolved, "milestone", "reopen", res["id"])
|
|
2756
|
+
return jsonify({"reopened": True, "milestone": res})
|
|
2743
2757
|
res = store.update_milestone(ms_id, expected_rev=data.get("expected_rev"),
|
|
2744
2758
|
**(data.get("fields") or {}))
|
|
2745
2759
|
if "error" in res:
|
|
@@ -1105,7 +1105,9 @@ async def c3_task(
|
|
|
1105
1105
|
Time: time_add (minutes 1-1440 [+note/due_date=date/task_id]), time_update / time_delete (ref=entry id),
|
|
1106
1106
|
time_list (manual entries + recent auto sessions), time_summary (today/7d/30d, auto vs manual).
|
|
1107
1107
|
Auto-tracking: server startup + tool calls ping .c3/time; idle gaps >15min close a session.
|
|
1108
|
-
Milestones: milestone_add (name [+target_date]), milestone_update, milestone_list (with progress %),
|
|
1108
|
+
Milestones: milestone_add (name [+target_date]), milestone_update, milestone_list (with progress %),
|
|
1109
|
+
milestone_complete (close a shipped milestone; refuses while open tasks remain; tasks KEEP their link),
|
|
1110
|
+
milestone_reopen (undo complete), milestone_archive (removal: detaches tasks).
|
|
1109
1111
|
Notes: note_add (note [+kind=decision] [+task_id]), note_list.
|
|
1110
1112
|
History: history ([+task_id] [+limit]) — append-only event log (who/what/when, before->after), newest first.
|
|
1111
1113
|
task_id accepts any unique id prefix (>=4 chars); milestone accepts id or unique name.
|
|
@@ -1295,6 +1295,20 @@ def api_pm_milestone():
|
|
|
1295
1295
|
if not ms_id:
|
|
1296
1296
|
return jsonify({"error": "id is required"}), 400
|
|
1297
1297
|
if request.method == "PUT":
|
|
1298
|
+
# {complete: true} / {reopen: true} switch lifecycle; tasks keep
|
|
1299
|
+
# their milestone link (unlike DELETE = archive + detach).
|
|
1300
|
+
if data.get("complete"):
|
|
1301
|
+
res = store.complete_milestone(ms_id)
|
|
1302
|
+
if "error" in res:
|
|
1303
|
+
return jsonify(res), 400
|
|
1304
|
+
_pm_audit("milestone", "complete", res["id"])
|
|
1305
|
+
return jsonify({"completed": True, "milestone": res})
|
|
1306
|
+
if data.get("reopen"):
|
|
1307
|
+
res = store.reopen_milestone(ms_id)
|
|
1308
|
+
if "error" in res:
|
|
1309
|
+
return jsonify(res), 400
|
|
1310
|
+
_pm_audit("milestone", "reopen", res["id"])
|
|
1311
|
+
return jsonify({"reopened": True, "milestone": res})
|
|
1298
1312
|
res = store.update_milestone(ms_id, expected_rev=data.get("expected_rev"),
|
|
1299
1313
|
**(data.get("fields") or {}))
|
|
1300
1314
|
if "error" in res:
|
|
@@ -69,6 +69,45 @@ _SOFT_WARN = re.compile(
|
|
|
69
69
|
|
|
70
70
|
_DEFAULT_TIMEOUT = 60
|
|
71
71
|
_MAX_TIMEOUT = 600
|
|
72
|
+
|
|
73
|
+
# The transport's own ceiling, and the reason _MAX_TIMEOUT alone is a lie.
|
|
74
|
+
#
|
|
75
|
+
# An MCP client kills a tool call at MCP_TOOL_TIMEOUT (Claude Code ships
|
|
76
|
+
# 120_000 ms and the value is set per-environment) — a limit this process does
|
|
77
|
+
# not choose and cannot raise. Until this existed, `c3_shell(timeout=600)` was
|
|
78
|
+
# accepted, clamped to 600, and then killed by the client at 120s with the
|
|
79
|
+
# subprocess still running: the caller saw the call "moved to background" and
|
|
80
|
+
# then fail, with no line anywhere naming the real limit or attributing the
|
|
81
|
+
# kill. The subprocess was NOT reaped by us, because our own deadline never
|
|
82
|
+
# arrived.
|
|
83
|
+
#
|
|
84
|
+
# The cost was not hypothetical. Two Higgsfield image generations (2-4 min
|
|
85
|
+
# each) were requested at timeout=420, killed at 120s, and the remote jobs
|
|
86
|
+
# completed and were BILLED while the local process died before downloading —
|
|
87
|
+
# one image landed, one was paid for and stranded.
|
|
88
|
+
#
|
|
89
|
+
# So: discover the client's ceiling, run just inside it, and SAY SO. Running
|
|
90
|
+
# inside it means OUR deadline fires first, which turns a phantom
|
|
91
|
+
# client-side kill into an ordinary `[c3_shell:TIMEOUT]` with stdout, a
|
|
92
|
+
# duration, and a process tree we actually killed.
|
|
93
|
+
_TRANSPORT_MARGIN_S = 5
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def _transport_ceiling_s() -> int | None:
|
|
97
|
+
"""Seconds this call may run before the MCP client kills it, if knowable.
|
|
98
|
+
|
|
99
|
+
None when the variable is unset or unparseable — then nothing is capped
|
|
100
|
+
and behaviour is exactly what it was, because a guess here would cap
|
|
101
|
+
legitimate work on a client with no such limit.
|
|
102
|
+
"""
|
|
103
|
+
raw = (os.environ.get("MCP_TOOL_TIMEOUT") or "").strip()
|
|
104
|
+
if not raw:
|
|
105
|
+
return None
|
|
106
|
+
try:
|
|
107
|
+
ceiling = int(float(raw)) // 1000
|
|
108
|
+
except (TypeError, ValueError):
|
|
109
|
+
return None
|
|
110
|
+
return ceiling if ceiling > _TRANSPORT_MARGIN_S else None
|
|
72
111
|
_FILTER_THRESHOLD_LINES = 30
|
|
73
112
|
_JQ_INVOCATION = re.compile(r"(?:^|&&|\|\||[;|(])\s*jq(?:\s|$)", re.IGNORECASE)
|
|
74
113
|
|
|
@@ -468,6 +507,13 @@ async def handle_shell(cmd: str, cwd: str, timeout: int, filter_output: bool,
|
|
|
468
507
|
)
|
|
469
508
|
|
|
470
509
|
timeout = max(1, min(int(timeout or _DEFAULT_TIMEOUT), _MAX_TIMEOUT))
|
|
510
|
+
# Cap to what the transport will actually allow, and remember that we did
|
|
511
|
+
# so — the caller asked for a number, and a number quietly not honoured is
|
|
512
|
+
# the whole defect (see _transport_ceiling_s).
|
|
513
|
+
capped_from = 0
|
|
514
|
+
_ceiling = _transport_ceiling_s()
|
|
515
|
+
if _ceiling is not None and timeout > _ceiling - _TRANSPORT_MARGIN_S:
|
|
516
|
+
capped_from, timeout = timeout, _ceiling - _TRANSPORT_MARGIN_S
|
|
471
517
|
work_cwd = cwd or svc.project_path
|
|
472
518
|
work_cwd = str(Path(work_cwd).resolve())
|
|
473
519
|
|
|
@@ -601,6 +647,16 @@ async def handle_shell(cmd: str, cwd: str, timeout: int, filter_output: bool,
|
|
|
601
647
|
warn = ""
|
|
602
648
|
if _SOFT_WARN.search(cmd):
|
|
603
649
|
warn = "[c3_shell:warn] destructive pattern detected — verify before re-running\n"
|
|
650
|
+
if capped_from:
|
|
651
|
+
# Named at the moment of the mistake, not in documentation nobody
|
|
652
|
+
# reads at the moment they need it. The alternative IS the escape
|
|
653
|
+
# hatch, so the line says which one.
|
|
654
|
+
warn += (
|
|
655
|
+
f"[c3_shell:capped] timeout={capped_from}s was requested but this "
|
|
656
|
+
f"MCP client kills a tool call at {_ceiling}s; ran with {timeout}s. "
|
|
657
|
+
f"For longer work use the native Bash tool with "
|
|
658
|
+
f"run_in_background, which is not bound by this limit.\n"
|
|
659
|
+
)
|
|
604
660
|
|
|
605
661
|
if result["timed_out"]:
|
|
606
662
|
status = "TIMEOUT"
|
|
@@ -5,7 +5,8 @@ READ_ACTIONS = {"list", "get", "board", "history", "report",
|
|
|
5
5
|
|
|
6
6
|
_TASK_ACTIONS = ("add, update, done, list, get, board, history, report, archive, "
|
|
7
7
|
"block, unblock, link, unlink, "
|
|
8
|
-
"milestone_add, milestone_update, milestone_list,
|
|
8
|
+
"milestone_add, milestone_update, milestone_list, "
|
|
9
|
+
"milestone_complete, milestone_reopen, milestone_archive, "
|
|
9
10
|
"note_add, note_list, "
|
|
10
11
|
"time_add, time_update, time_delete, time_list, time_summary")
|
|
11
12
|
|
|
@@ -368,6 +369,26 @@ def handle_task(action, svc, finalize, *, title="", task_id="", status="",
|
|
|
368
369
|
return done_resp(f"[task:error] {res['error']}", "error")
|
|
369
370
|
return done_resp(f"[milestone:updated] {res['id'][:8]} \"{res['name']}\"", "updated")
|
|
370
371
|
|
|
372
|
+
if action == "milestone_complete":
|
|
373
|
+
if not milestone:
|
|
374
|
+
return done_resp("[task:error] milestone_complete requires milestone.", "error")
|
|
375
|
+
ms = store.resolve_milestone(milestone)
|
|
376
|
+
if ms is None:
|
|
377
|
+
return done_resp(f"[task:error] no milestone matches: {milestone}", "error")
|
|
378
|
+
res = store.complete_milestone(ms["id"])
|
|
379
|
+
if "error" in res:
|
|
380
|
+
return done_resp(f"[task:error] {res['error']}", "error")
|
|
381
|
+
return done_resp(f"[milestone:completed] \"{res['name']}\" "
|
|
382
|
+
f"(tasks keep their milestone link)", "completed")
|
|
383
|
+
|
|
384
|
+
if action == "milestone_reopen":
|
|
385
|
+
if not milestone:
|
|
386
|
+
return done_resp("[task:error] milestone_reopen requires milestone.", "error")
|
|
387
|
+
res = store.reopen_milestone(milestone)
|
|
388
|
+
if "error" in res:
|
|
389
|
+
return done_resp(f"[task:error] {res['error']}", "error")
|
|
390
|
+
return done_resp(f"[milestone:reopened] \"{res['name']}\"", "reopened")
|
|
391
|
+
|
|
371
392
|
if action == "milestone_archive":
|
|
372
393
|
if not milestone:
|
|
373
394
|
return done_resp("[task:error] milestone_archive requires milestone.", "error")
|
{code_context_control-2.85.0 → code_context_control-2.86.0/code_context_control.egg-info}/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: code-context-control
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.86.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
|
|
@@ -178,7 +178,7 @@ Twelve tabs. The dashboard above shows token savings, indexed files, the live se
|
|
|
178
178
|
<img src="https://raw.githubusercontent.com/drknowhow/code-context-control/main/docs/screenshots/2026-07/ui_tasks.png" alt="C3 Tasks" width="900">
|
|
179
179
|
</p>
|
|
180
180
|
|
|
181
|
-
**Tasks** (v2.45.0, extended v2.53.0) is a durable per-project tracker — dependencies and subtasks, milestones, decision notes, full event history, health reports, and both automatic and manual time tracking. It rolls up into the Hub's cross-project board.
|
|
181
|
+
**Tasks** (v2.45.0, extended v2.53.0) is a durable per-project tracker — dependencies and subtasks, milestones, decision notes, full event history, health reports, and both automatic and manual time tracking. It rolls up into the Hub's cross-project board. Shipped milestones can be **completed** (v2.86.0) — they leave the board while their tasks keep the milestone link, unlike archiving, which detaches them.
|
|
182
182
|
|
|
183
183
|
**Instructions** keeps your agent-facing docs in sync. C3-generated content sits inside a `<!-- C3:BEGIN … -->` block; anything you write outside it is preserved. Since v2.60.0 generated docs point at `.c3/MAP.md` — a machine-owned, byte-stable repo map C3 refreshes automatically — instead of embedding a tree that goes stale. `AGENTS.md` serves both Codex and Antigravity; `GEMINI.md` is read if present but no longer generated (the Gemini CLI profile was removed in v2.52).
|
|
184
184
|
|
|
@@ -243,6 +243,7 @@ c3 access mask activate # purge pre-mask artifacts, buil
|
|
|
243
243
|
- **`deny` means deny-enumerate too** — denied paths never appear in search results, maps, or the vector index.
|
|
244
244
|
- **Masked means read-only, always.** Cropped rows have no inverse, so an edit in transformed coordinates would corrupt the one file you protected.
|
|
245
245
|
- **Four deterministic presets, no LLM in the read path:** `redact_secrets`, `redact_columns` (salted one-way pseudonyms — joins survive, no reverse dictionary), `sample_rows`, `signatures_only`.
|
|
246
|
+
- **Sensible defaults out of the box** (v2.86.0). A fresh install seeds `*.pem`, `id_rsa*`, and `*.key` as deny rules in global scope — visible in `c3 access list` and removable like any rule you wrote yourself. Delete one and it stays deleted.
|
|
246
247
|
- **Rule changes are human-only** (UI tab or CLI) and ledger-logged. Agents have no mutation surface.
|
|
247
248
|
- **Built-ins can be switched off when you need to** (v2.65.0). `**/.env*`, `**/.c3/**`, `**/.claude/settings*.json` and `**/.git/**` yield to `c3 access builtin disable <glob>`, which makes you retype the glob first. It takes **two keys** — a config entry *and* a keyring attestation — so an agent that manages to write `config.json` still cannot grant itself write access to your settings. The credential vault stays absolute.
|
|
248
249
|
- **Honest coverage.** This guards *cooperative* agents against mistakes and prompt injection. It is not a sandbox — a raw shell outside C3's tools still sees the real bytes.
|
|
@@ -811,6 +811,20 @@ def mobile_pm_milestone():
|
|
|
811
811
|
return jsonify({"error": "id is required"}), 400
|
|
812
812
|
|
|
813
813
|
if request.method == "PUT":
|
|
814
|
+
# {complete: true} / {reopen: true} switch lifecycle; tasks keep
|
|
815
|
+
# their milestone link (unlike DELETE = archive + detach).
|
|
816
|
+
if data.get("complete"):
|
|
817
|
+
res = store.complete_milestone(ms_id)
|
|
818
|
+
if "error" in res:
|
|
819
|
+
return _pm_error(res)
|
|
820
|
+
_pm_audit(resolved, "milestone", "complete", res["id"])
|
|
821
|
+
return jsonify({"completed": True, "milestone": res})
|
|
822
|
+
if data.get("reopen"):
|
|
823
|
+
res = store.reopen_milestone(ms_id)
|
|
824
|
+
if "error" in res:
|
|
825
|
+
return _pm_error(res)
|
|
826
|
+
_pm_audit(resolved, "milestone", "reopen", res["id"])
|
|
827
|
+
return jsonify({"reopened": True, "milestone": res})
|
|
814
828
|
res = store.update_milestone(ms_id, expected_rev=data.get("expected_rev"),
|
|
815
829
|
**(data.get("fields") or {}))
|
|
816
830
|
if "error" in res:
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "code-context-control"
|
|
7
|
-
version = "2.
|
|
7
|
+
version = "2.86.0"
|
|
8
8
|
description = "Local MCP code-intelligence for AI coding tools: surgical search/read/edit, agent-config version history, path-level access + masking guards, and a multi-project hub."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.10"
|
|
@@ -1087,6 +1087,33 @@ def _write_scope_config(cfg: Path, data: dict) -> None:
|
|
|
1087
1087
|
os.replace(tmp, cfg)
|
|
1088
1088
|
|
|
1089
1089
|
|
|
1090
|
+
def seed_default_global_rules() -> dict:
|
|
1091
|
+
"""Seed DEFAULT_GLOBAL_RULES as deny rules in GLOBAL scope, once ever.
|
|
1092
|
+
|
|
1093
|
+
Spec §1: the defaults ship as visible, removable rules — so they are
|
|
1094
|
+
written to ``~/.c3/config.json`` only when that file has never carried
|
|
1095
|
+
an ``access`` section. Any existing section (even an emptied one) means
|
|
1096
|
+
the user has touched the scope and removal stays sticky. A corrupt or
|
|
1097
|
+
unreadable config is never rewritten. Never raises: install and CLI
|
|
1098
|
+
call this on every run and must not break on a bad home dir.
|
|
1099
|
+
|
|
1100
|
+
Returns {"seeded": bool, "rules": [...]} — ``rules`` only when seeded.
|
|
1101
|
+
"""
|
|
1102
|
+
try:
|
|
1103
|
+
cfg = _scope_config_path("global")
|
|
1104
|
+
data = {}
|
|
1105
|
+
if cfg.is_file():
|
|
1106
|
+
data = json.loads(cfg.read_text(encoding="utf-8")) or {}
|
|
1107
|
+
if not isinstance(data, dict) or "access" in data:
|
|
1108
|
+
return {"seeded": False}
|
|
1109
|
+
data["access"] = {_KIND_DENY: [_norm_glob(g)
|
|
1110
|
+
for g in DEFAULT_GLOBAL_RULES]}
|
|
1111
|
+
_write_scope_config(cfg, data)
|
|
1112
|
+
return {"seeded": True, "rules": list(DEFAULT_GLOBAL_RULES)}
|
|
1113
|
+
except Exception:
|
|
1114
|
+
return {"seeded": False}
|
|
1115
|
+
|
|
1116
|
+
|
|
1090
1117
|
def set_rule(glob, kind: str, scope: str, project_path: str = ".") -> dict:
|
|
1091
1118
|
"""Add one rule to *scope*'s config. Human surfaces only; callers log.
|
|
1092
1119
|
|
|
@@ -65,6 +65,39 @@ def gitignore_dir_names(root) -> set:
|
|
|
65
65
|
return gitignore_dir_patterns(root)[0]
|
|
66
66
|
|
|
67
67
|
|
|
68
|
+
def is_nested_checkout(path) -> bool:
|
|
69
|
+
"""True when ``path`` is the root of a DIFFERENT checkout than ours.
|
|
70
|
+
|
|
71
|
+
``SKIP_DIRS`` cannot express this, because it matches directory NAMES and
|
|
72
|
+
a nested checkout is named whatever somebody called it. A linked git
|
|
73
|
+
worktree is the case that matters: its marker is a ``.git`` FILE holding
|
|
74
|
+
``gitdir: …`` rather than a ``.git`` directory, so pruning the name
|
|
75
|
+
``.git`` skips a file that was never a directory and descends into the
|
|
76
|
+
entire copy of the repository sitting beside it.
|
|
77
|
+
|
|
78
|
+
Measured on the Yep project, 2026-08-11 — 112 registered worktrees, most
|
|
79
|
+
of them agent scratch under ``.claude/worktrees/``:
|
|
80
|
+
|
|
81
|
+
.py files in the real tree 1,108
|
|
82
|
+
.py files under worktree dirs 100,629 (91x amplification)
|
|
83
|
+
|
|
84
|
+
A cross-project exact search there took 147.6s, against 0.11s to build
|
|
85
|
+
the runtime. The MCP transport kills a tool call at 120s, so the search
|
|
86
|
+
could never return — not slow, unreachable, and the reason
|
|
87
|
+
``c3_project`` was unusable against that project at all.
|
|
88
|
+
|
|
89
|
+
Indexing them is also wrong on the merits, independent of cost: they are
|
|
90
|
+
other commits of files this project already has, so every hit is
|
|
91
|
+
duplicated ~112 times and the top result is whichever stale copy sorted
|
|
92
|
+
first. The search that exposed this returned a hit inside
|
|
93
|
+
``.claude/worktrees/bridge-cse_01MPoh…`` rather than from src/.
|
|
94
|
+
"""
|
|
95
|
+
try:
|
|
96
|
+
return os.path.exists(os.path.join(str(path), '.git'))
|
|
97
|
+
except (OSError, ValueError):
|
|
98
|
+
return False
|
|
99
|
+
|
|
100
|
+
|
|
68
101
|
def make_dir_pruner(root, extra_skip=(), respect_gitignore: bool = True):
|
|
69
102
|
"""Predicate ``dirname -> bool`` (True = prune this directory).
|
|
70
103
|
|
|
@@ -177,6 +210,8 @@ def iter_files(
|
|
|
177
210
|
continue
|
|
178
211
|
if guard_excluded(os.path.join(dirpath, d)):
|
|
179
212
|
continue # denied subtree — never descended, never listed
|
|
213
|
+
if is_nested_checkout(os.path.join(dirpath, d)):
|
|
214
|
+
continue # another checkout's copy of files we already index
|
|
180
215
|
kept.append(d)
|
|
181
216
|
dirnames[:] = kept
|
|
182
217
|
seen += len(filenames) + len(kept)
|
|
@@ -864,6 +864,69 @@ class TaskStore:
|
|
|
864
864
|
self._save(doc)
|
|
865
865
|
return {**ms, "detached_tasks": detached}
|
|
866
866
|
|
|
867
|
+
def complete_milestone(self, milestone_id) -> dict:
|
|
868
|
+
"""Close a finished milestone; its tasks KEEP their milestone link.
|
|
869
|
+
|
|
870
|
+
The happy-path close, distinct from archive_milestone (removal:
|
|
871
|
+
detaches tasks, eligible for purge). A completed milestone leaves
|
|
872
|
+
default listings, the board, and the report, but history still
|
|
873
|
+
records which tasks shipped under it. Refuses while open active
|
|
874
|
+
tasks remain; undo with reopen_milestone().
|
|
875
|
+
"""
|
|
876
|
+
with self._guard():
|
|
877
|
+
doc = self._load()
|
|
878
|
+
ms = self._resolve(doc["milestones"], milestone_id)
|
|
879
|
+
if ms is None:
|
|
880
|
+
return {"error": f"no milestone matches: {milestone_id}"}
|
|
881
|
+
old = ms.get("lifecycle", "active")
|
|
882
|
+
if old != "active":
|
|
883
|
+
return {"error": f"milestone is {old}, not active"}
|
|
884
|
+
open_tasks = [t for t in doc["tasks"]
|
|
885
|
+
if t.get("milestone_id") == ms["id"]
|
|
886
|
+
and t.get("lifecycle", "active") == "active"
|
|
887
|
+
and t.get("status") != "done"]
|
|
888
|
+
if open_tasks:
|
|
889
|
+
names = ", ".join(t["id"][:8] for t in open_tasks[:5])
|
|
890
|
+
return {"error": f"{len(open_tasks)} open task(s) block "
|
|
891
|
+
f"completion: {names}"}
|
|
892
|
+
now = _now()
|
|
893
|
+
ms["lifecycle"] = "completed"
|
|
894
|
+
ms["completed_at"] = now
|
|
895
|
+
ms["updated_at"] = now
|
|
896
|
+
self._event("milestone", "complete", ms["id"],
|
|
897
|
+
patch={"lifecycle": [old, "completed"]})
|
|
898
|
+
self._save(doc)
|
|
899
|
+
return dict(ms)
|
|
900
|
+
|
|
901
|
+
def reopen_milestone(self, milestone_id) -> dict:
|
|
902
|
+
"""Completed -> active again; clears completed_at.
|
|
903
|
+
|
|
904
|
+
Accepts id, unique id prefix, or — because resolve_milestone's
|
|
905
|
+
name matching deliberately covers only ACTIVE milestones — a
|
|
906
|
+
unique case-insensitive name among the completed ones.
|
|
907
|
+
"""
|
|
908
|
+
with self._guard():
|
|
909
|
+
doc = self._load()
|
|
910
|
+
ms = self._resolve(doc["milestones"], milestone_id)
|
|
911
|
+
if ms is None:
|
|
912
|
+
want = (milestone_id or "").strip().lower()
|
|
913
|
+
matches = [m for m in doc["milestones"]
|
|
914
|
+
if m.get("lifecycle") == "completed"
|
|
915
|
+
and (m.get("name") or "").lower() == want]
|
|
916
|
+
ms = matches[0] if len(matches) == 1 else None
|
|
917
|
+
if ms is None:
|
|
918
|
+
return {"error": f"no milestone matches: {milestone_id}"}
|
|
919
|
+
old = ms.get("lifecycle", "active")
|
|
920
|
+
if old != "completed":
|
|
921
|
+
return {"error": f"milestone is {old}, not completed"}
|
|
922
|
+
ms["lifecycle"] = "active"
|
|
923
|
+
ms["completed_at"] = None
|
|
924
|
+
ms["updated_at"] = _now()
|
|
925
|
+
self._event("milestone", "reopen", ms["id"],
|
|
926
|
+
patch={"lifecycle": [old, "active"]})
|
|
927
|
+
self._save(doc)
|
|
928
|
+
return dict(ms)
|
|
929
|
+
|
|
867
930
|
def resolve_milestone(self, ref: str):
|
|
868
931
|
"""Resolve by id, unique id prefix, or unique case-insensitive name."""
|
|
869
932
|
doc = self._load()
|
|
@@ -289,5 +289,77 @@ class TestEnforce(GuardBase):
|
|
|
289
289
|
ag.enforce(str(self.proj / "src/ok.py"), "read", str(self.proj))
|
|
290
290
|
|
|
291
291
|
|
|
292
|
+
class TestSeedDefaults(GuardBase):
|
|
293
|
+
"""seed_default_global_rules — spec §1 removable defaults, sticky removal."""
|
|
294
|
+
|
|
295
|
+
def setUp(self):
|
|
296
|
+
super().setUp()
|
|
297
|
+
import unittest.mock as mock
|
|
298
|
+
self._home = Path(tempfile.mkdtemp())
|
|
299
|
+
self._gb = mock.patch.object(ag, "_global_base",
|
|
300
|
+
return_value=self._home)
|
|
301
|
+
self._gb.start()
|
|
302
|
+
self.global_cfg = self._home / ".c3" / "config.json"
|
|
303
|
+
|
|
304
|
+
def tearDown(self):
|
|
305
|
+
self._gb.stop()
|
|
306
|
+
import shutil
|
|
307
|
+
shutil.rmtree(self._home, ignore_errors=True)
|
|
308
|
+
super().tearDown()
|
|
309
|
+
|
|
310
|
+
def test_seeds_on_first_run(self):
|
|
311
|
+
res = ag.seed_default_global_rules()
|
|
312
|
+
self.assertTrue(res["seeded"])
|
|
313
|
+
data = json.loads(self.global_cfg.read_text(encoding="utf-8"))
|
|
314
|
+
self.assertEqual(data["access"]["deny"],
|
|
315
|
+
list(ag.DEFAULT_GLOBAL_RULES))
|
|
316
|
+
|
|
317
|
+
def test_seeded_rules_are_enforced(self):
|
|
318
|
+
ag.seed_default_global_rules()
|
|
319
|
+
d = ag.check(str(self.proj / "server.pem"), "read", str(self.proj))
|
|
320
|
+
self.assertIsNotNone(d)
|
|
321
|
+
self.assertEqual(d.scope, "global")
|
|
322
|
+
|
|
323
|
+
def test_second_run_is_noop(self):
|
|
324
|
+
ag.seed_default_global_rules()
|
|
325
|
+
self.assertFalse(ag.seed_default_global_rules()["seeded"])
|
|
326
|
+
|
|
327
|
+
def test_removal_stays_sticky(self):
|
|
328
|
+
ag.seed_default_global_rules()
|
|
329
|
+
for glob in ag.DEFAULT_GLOBAL_RULES:
|
|
330
|
+
ag.remove_rule(glob, "deny", "global")
|
|
331
|
+
self.assertFalse(ag.seed_default_global_rules()["seeded"])
|
|
332
|
+
data = json.loads(self.global_cfg.read_text(encoding="utf-8"))
|
|
333
|
+
self.assertEqual(data["access"]["deny"], [])
|
|
334
|
+
|
|
335
|
+
def test_existing_access_section_never_touched(self):
|
|
336
|
+
self._write_access({"deny": ["mine/**"]}, base=self._home)
|
|
337
|
+
self.assertFalse(ag.seed_default_global_rules()["seeded"])
|
|
338
|
+
data = json.loads(self.global_cfg.read_text(encoding="utf-8"))
|
|
339
|
+
self.assertEqual(data["access"]["deny"], ["mine/**"])
|
|
340
|
+
|
|
341
|
+
def test_config_without_access_section_preserves_other_keys(self):
|
|
342
|
+
self.global_cfg.parent.mkdir(parents=True, exist_ok=True)
|
|
343
|
+
self.global_cfg.write_text(json.dumps({"other": {"k": 1}}),
|
|
344
|
+
encoding="utf-8")
|
|
345
|
+
res = ag.seed_default_global_rules()
|
|
346
|
+
self.assertTrue(res["seeded"])
|
|
347
|
+
data = json.loads(self.global_cfg.read_text(encoding="utf-8"))
|
|
348
|
+
self.assertEqual(data["other"], {"k": 1})
|
|
349
|
+
self.assertEqual(data["access"]["deny"],
|
|
350
|
+
list(ag.DEFAULT_GLOBAL_RULES))
|
|
351
|
+
|
|
352
|
+
def test_corrupt_config_never_rewritten(self):
|
|
353
|
+
self.global_cfg.parent.mkdir(parents=True, exist_ok=True)
|
|
354
|
+
self.global_cfg.write_text("{nope", encoding="utf-8")
|
|
355
|
+
self.assertFalse(ag.seed_default_global_rules()["seeded"])
|
|
356
|
+
self.assertEqual(self.global_cfg.read_text(encoding="utf-8"), "{nope")
|
|
357
|
+
|
|
358
|
+
def test_no_home_is_a_noop(self):
|
|
359
|
+
import unittest.mock as mock
|
|
360
|
+
with mock.patch.object(ag, "_global_base", return_value=None):
|
|
361
|
+
self.assertFalse(ag.seed_default_global_rules()["seeded"])
|
|
362
|
+
|
|
363
|
+
|
|
292
364
|
if __name__ == "__main__":
|
|
293
365
|
unittest.main()
|