code-context-control 2.111.0__tar.gz → 2.113.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.111.0 → code_context_control-2.113.0}/PKG-INFO +1 -1
- {code_context_control-2.111.0 → code_context_control-2.113.0}/cli/c3.py +1 -1
- {code_context_control-2.111.0 → code_context_control-2.113.0}/cli/mcp_server.py +28 -5
- {code_context_control-2.111.0 → code_context_control-2.113.0}/cli/tools/shell.py +397 -62
- code_context_control-2.113.0/cli/tools/shell_parsers.py +683 -0
- code_context_control-2.113.0/cli/tools/shell_render.py +481 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/code_context_control.egg-info/PKG-INFO +1 -1
- {code_context_control-2.111.0 → code_context_control-2.113.0}/code_context_control.egg-info/SOURCES.txt +6 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/pyproject.toml +1 -1
- code_context_control-2.113.0/services/shell_output.py +1051 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_c3_shell.py +37 -12
- code_context_control-2.113.0/tests/test_shell_budget_s1.py +334 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_shell_eval.py +18 -9
- code_context_control-2.113.0/tests/test_shell_output.py +727 -0
- code_context_control-2.113.0/tests/test_shell_parsers_s2.py +566 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_shell_telemetry_s0.py +12 -5
- {code_context_control-2.111.0 → code_context_control-2.113.0}/LICENSE +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/README.md +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/cli/__init__.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/cli/_hook_utils.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/cli/_shell_writes.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/cli/commands/__init__.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/cli/commands/common.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/cli/commands/parser.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/cli/docs.html +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/cli/edits.html +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/cli/guide/access.html +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/cli/guide/bitbucket.html +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/cli/guide/credentials.html +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/cli/guide/getting-started.html +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/cli/guide/index.html +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/cli/guide/masking.html +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/cli/guide/oracle.html +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/cli/guide/shared.css +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/cli/guide/tools.html +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/cli/guide/workflow.html +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/cli/hook_access_guard.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/cli/hook_artifact.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/cli/hook_auto_snapshot.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/cli/hook_c3_signal.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/cli/hook_c3read.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/cli/hook_dispatch.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/cli/hook_edit_ledger.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/cli/hook_edit_unlock.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/cli/hook_filter.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/cli/hook_ghost_files.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/cli/hook_pretool_enforce.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/cli/hook_prompt_recall.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/cli/hook_read.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/cli/hook_session_stats.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/cli/hook_terse_advisor.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/cli/hub_server.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/cli/hub_ui/app.js +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/cli/hub_ui/components/add_project.js +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/cli/hub_ui/components/config_editor.js +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/cli/hub_ui/components/drill_artifacts.js +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/cli/hub_ui/components/drill_health.js +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/cli/hub_ui/components/drill_panel.js +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/cli/hub_ui/components/drill_subprojects.js +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/cli/hub_ui/components/drill_tasks.js +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/cli/hub_ui/components/drill_views.js +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/cli/hub_ui/components/global_search.js +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/cli/hub_ui/components/hub_access.js +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/cli/hub_ui/components/hub_ci.js +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/cli/hub_ui/components/hub_cred_audit.js +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/cli/hub_ui/components/hub_credentials.js +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/cli/hub_ui/components/hub_enforcement.js +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/cli/hub_ui/components/hub_locks.js +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/cli/hub_ui/components/hub_tokens.js +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/cli/hub_ui/components/mcp_manager.js +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/cli/hub_ui/components/modals.js +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/cli/hub_ui/components/project_card.js +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/cli/hub_ui/components/project_tree.js +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/cli/hub_ui/components/session_drawer.js +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/cli/hub_ui/components/settings_modal.js +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/cli/hub_ui/components/sidebar.js +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/cli/hub_ui/components/summary_bar.js +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/cli/hub_ui/components/task_board.js +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/cli/hub_ui/components/toasts.js +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/cli/hub_ui/components/topbar.js +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/cli/hub_ui/state.js +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/cli/hub_ui.html +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/cli/mcp_proxy.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/cli/progress.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/cli/server.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/cli/tools/__init__.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/cli/tools/_grants.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/cli/tools/_helpers.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/cli/tools/agent.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/cli/tools/artifacts.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/cli/tools/bitbucket.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/cli/tools/ci.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/cli/tools/compress.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/cli/tools/credentials.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/cli/tools/delegate.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/cli/tools/edit.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/cli/tools/edit_verify.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/cli/tools/edits.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/cli/tools/federate.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/cli/tools/filter.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/cli/tools/impact.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/cli/tools/jira.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/cli/tools/locks.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/cli/tools/memory.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/cli/tools/override.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/cli/tools/project.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/cli/tools/read.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/cli/tools/search.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/cli/tools/session.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/cli/tools/status.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/cli/tools/tasks.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/cli/tools/validate.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/cli/ui/api.js +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/cli/ui/app.js +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/cli/ui/components/access.js +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/cli/ui/components/bitbucket.js +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/cli/ui/components/chat.js +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/cli/ui/components/credentials.js +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/cli/ui/components/dashboard.js +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/cli/ui/components/edits.js +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/cli/ui/components/enforcement.js +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/cli/ui/components/instructions.js +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/cli/ui/components/jira.js +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/cli/ui/components/memory.js +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/cli/ui/components/sessions.js +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/cli/ui/components/settings.js +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/cli/ui/components/sidebar.js +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/cli/ui/components/tasks.js +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/cli/ui/icons.js +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/cli/ui/pm_shared.js +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/cli/ui/shared.js +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/cli/ui/theme.js +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/cli/ui.html +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/cli/ui_legacy.html +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/cli/ui_nano.html +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/code_context_control.egg-info/dependency_links.txt +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/code_context_control.egg-info/entry_points.txt +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/code_context_control.egg-info/requires.txt +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/code_context_control.egg-info/top_level.txt +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/core/__init__.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/core/config.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/core/ide.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/core/mcp_toml.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/core/web_security.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/oracle/__init__.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/oracle/config.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/oracle/mcp_oracle.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/oracle/oracle_server.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/oracle/oracle_ui.html +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/oracle/services/__init__.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/oracle/services/activity_reporter.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/oracle/services/api_auth.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/oracle/services/c3_bridge.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/oracle/services/chat_engine.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/oracle/services/chat_poll.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/oracle/services/chat_store.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/oracle/services/cross_memory.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/oracle/services/discovery_audit.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/oracle/services/federated_graph.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/oracle/services/health_checker.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/oracle/services/insight_engine.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/oracle/services/local_session.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/oracle/services/memory_reader.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/oracle/services/memory_writer.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/oracle/services/mobile_api.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/oracle/services/project_scanner.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/oracle/services/review_agent.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/oracle/services/tool_executor.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/oracle/services/tool_registry.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/oracle/ui/activity.js +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/oracle/ui/agents.js +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/oracle/ui/app.js +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/oracle/ui/busy.js +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/oracle/ui/chat/conversations.js +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/oracle/ui/chat/input.js +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/oracle/ui/chat/markdown.js +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/oracle/ui/chat/send.js +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/oracle/ui/chat/stream_renderer.js +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/oracle/ui/chat/toolbar.js +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/oracle/ui/core.js +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/oracle/ui/crossgraph.js +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/oracle/ui/header.js +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/oracle/ui/insights.js +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/oracle/ui/projects.js +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/oracle/ui/qrcode.js +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/oracle/ui/settings.js +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/oracle/ui/suggestions.js +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/oracle/ui/theme_tabs.js +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/services/__init__.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/services/access_guard.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/services/access_telemetry.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/services/activity_log.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/services/agent_base.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/services/agent_locks.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/services/agents.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/services/artifact_defs.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/services/artifact_store.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/services/auto_memory.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/services/background_service.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/services/bench/__init__.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/services/bench/external/__init__.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/services/bench/external/aider_polyglot.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/services/bench/external/swe_bench.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/services/bench/search_eval.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/services/bench/shell_eval.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/services/benchmark_dashboard.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/services/bitbucket_client.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/services/bitbucket_credentials.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/services/ci_act.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/services/ci_cache.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/services/ci_expr.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/services/ci_failures.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/services/ci_github.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/services/ci_impact.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/services/ci_intel.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/services/ci_runner.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/services/ci_workflow.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/services/circuit_breaker.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/services/claude_md.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/services/compressor.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/services/context_snapshot.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/services/conversation_store.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/services/cred_audit.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/services/cred_telemetry.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/services/credential_store.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/services/doc_index.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/services/e2e_benchmark.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/services/e2e_evaluator.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/services/e2e_tasks.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/services/edit_ledger.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/services/embedding_index.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/services/enforcement_policy.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/services/error_reporting.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/services/file_memory.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/services/git_context.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/services/hub_service.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/services/index_store.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/services/indexer.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/services/jira_client.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/services/jira_cloud.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/services/jira_credentials.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/services/jira_data_center.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/services/jira_links.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/services/lexical_index.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/services/mask_activation.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/services/mask_mirror.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/services/mask_presets.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/services/memory.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/services/memory_consolidator.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/services/memory_distiller.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/services/memory_graph.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/services/memory_grounder.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/services/memory_queue.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/services/memory_scorer.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/services/metrics.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/services/notifications.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/services/ollama_bridge.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/services/ollama_client.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/services/ollama_credentials.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/services/oracle_service.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/services/output_filter.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/services/override_grants.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/services/override_policy.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/services/override_requests.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/services/override_wake.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/services/parser.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/services/project_manager.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/services/project_runtime.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/services/protocol.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/services/proxy_state.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/services/repo_map.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/services/repo_shape.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/services/reranker.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/services/retention.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/services/retrieval.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/services/retrieval_broker.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/services/router.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/services/runtime.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/services/scanner.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/services/session_benchmark.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/services/session_manager.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/services/session_preloader.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/services/subprojects.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/services/task_store.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/services/telemetry.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/services/text_index.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/services/time_tracker.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/services/tool_classifier.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/services/transcript_index.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/services/validation_cache.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/services/vector_store.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/services/watcher.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/services/win_subprocess.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/setup.cfg +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_access_builtin_optout.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_access_guard.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_access_guard_meta.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_access_guard_shell_project.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_access_guard_surfaces.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_access_guard_wiring.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_activity_reporter.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_agent_locks.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_aider_polyglot.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_antigravity_transition.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_artifact_store.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_artifact_tool.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_background_service.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_bitbucket_cli_smoke.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_bitbucket_client.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_bitbucket_config_fallback.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_bitbucket_credentials.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_bitbucket_tool.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_builtin_modes.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_c3_bridge_project_artifacts.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_chat_poll.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_ci_act.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_ci_cache.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_ci_expr.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_ci_impact.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_ci_intel.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_ci_runner.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_ci_workflow.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_circuit_breaker.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_claude_md_merge.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_claude_md_updater.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_cli_smoke.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_compressor_large_file.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_confirm_guard.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_confirm_guard_wiring.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_cooccurrence_bounds.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_cred_audit.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_cred_telemetry.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_credential_login_kind.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_credential_store.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_credential_ui_parity.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_credentials_routes.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_credentials_tool.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_creds_cli_smoke.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_delegate_cascade.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_delegate_version_probe.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_e2e_benchmark.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_edit_ledger_deadline.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_edit_ledger_hook.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_edit_locking.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_edit_normalization.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_edit_verify.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_embedding_index_deadlock.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_enforcement_flip.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_enforcement_policy.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_enforcement_routes.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_env_parser.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_failed_calls_do_not_unlock.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_federated_graph.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_filter_backoff.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_ghost_files.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_ghost_generation.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_git_branch_awareness.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_hook_access_guard.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_hook_codex_compat.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_hook_dispatch.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_hook_pretool_enforce.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_hook_prompt_recall.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_hook_smoke.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_hook_state.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_hook_utf8_stdio.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_hub_credentials_route.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_hub_credentials_routes_write.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_hub_enforcement_routes.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_hub_inspect_api.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_hub_locks_routes.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_hub_oracle_service_routes.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_hub_override_routes.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_hub_server_smoke.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_hub_subproject_links.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_ide_workflow_adaptation.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_index_cap_not_hardcoded.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_init_clear_preserves_user_content.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_init_scan.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_install_mcp_entrypoint.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_jira_cli_smoke.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_jira_client.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_jira_config_fallback.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_jira_credentials.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_jira_links.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_jira_routes.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_jira_tool.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_lazy_store_init.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_mask_guard.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_mask_routes.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_mask_surfaces.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_mcp_host_guard.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_mcp_memory_timeout.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_mcp_server_smoke.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_mcp_toml.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_memory_distiller.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_memory_graph_api.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_memory_queue.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_memory_system.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_mobile_api.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_mobile_extras.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_mobile_override_routes.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_mobile_security_api.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_no_stale_model_pins.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_notification_dedup.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_notification_discipline.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_ollama_credentials.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_oracle_api_auth.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_oracle_apikey_api.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_oracle_c3_bridge.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_oracle_chat_engine.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_oracle_chat_store.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_oracle_discovery_api.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_oracle_discovery_audit.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_oracle_health_probe.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_oracle_local_auth.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_oracle_ollama_bridge.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_oracle_scanner_cache.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_oracle_security_fixes.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_oracle_session_bootstrap.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_oracle_subproject_awareness.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_oracle_ui_bundle.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_output_filter.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_override_grants.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_override_grants_mcp.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_override_requests.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_override_wake.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_permissions.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_pm_api.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_project_manager.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_project_manager_merge.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_project_tool.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_read_coercion.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_read_edit_parity.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_related_facts.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_repo_map.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_repo_shape.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_response_boilerplate.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_retention.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_review_digest.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_search_eval.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_search_p1.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_search_p2.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_search_p2b.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_search_p3.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_search_p4.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_search_p5.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_service_durability.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_session_benchmark.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_session_budget.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_shell_creds.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_shell_robustness.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_shell_write_ledger.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_shell_writes.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_subproject_clear_scope.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_subproject_depth_consumers.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_subproject_exclusion.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_subproject_federation.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_subproject_linkage_api.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_subprojects.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_swe_bench.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_task_store.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_task_tool.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_time_tracker.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_token_telemetry.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_token_tracking.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_tool_registry.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_ui_jsx_syntax.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_upgrade_and_version.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_validate.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_vault_write_guard.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_version_sync.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_web_security.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tests/test_windows_reliability.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tui/__init__.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tui/backend.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tui/main.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tui/screens/__init__.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tui/screens/benchmark_view.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tui/screens/claudemd_view.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tui/screens/compress_view.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tui/screens/index_view.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tui/screens/init_view.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tui/screens/mcp_view.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tui/screens/optimize_view.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tui/screens/pipe_view.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tui/screens/projects_view.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tui/screens/search_view.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tui/screens/session_view.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tui/screens/stats.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.0}/tui/screens/ui_view.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.113.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.113.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
|
|
@@ -883,16 +883,36 @@ async def c3_impact(target: str, file_path: str = "", mode: str = "symbol",
|
|
|
883
883
|
|
|
884
884
|
|
|
885
885
|
@mcp.tool()
|
|
886
|
-
async def c3_shell(cmd: str, cwd: str = "", timeout: int = 60,
|
|
886
|
+
async def c3_shell(cmd: str = "", cwd: str = "", timeout: int = 60,
|
|
887
887
|
filter_output: bool = True, log: bool = True,
|
|
888
888
|
env_creds: str = "",
|
|
889
|
+
output_id: str = "", output_action: str = "",
|
|
890
|
+
pattern: str = "", lines: str = "", stream: str = "stdout",
|
|
891
|
+
max_bytes: int = 0,
|
|
889
892
|
ctx: Context = None) -> str:
|
|
890
|
-
"""EXECUTE shell command — structured returns,
|
|
893
|
+
"""EXECUTE shell command — structured returns, budgeted output, ledger-aware.
|
|
891
894
|
Use for tests, git, build, scripts. Returns exit_code/stdout/stderr/duration_ms.
|
|
892
|
-
|
|
895
|
+
The response never exceeds 18 KiB (max_bytes may only lower it): a stream that does
|
|
896
|
+
not fit is clipped line by line and windowed head/tail with a note naming an
|
|
897
|
+
output_id; the raw streams are kept for 3 days OUTSIDE the project. Page them back
|
|
898
|
+
with output_id='o-…' and output_action='read' (lines='120-180'), 'search'
|
|
899
|
+
(pattern=regex), 'tail' (lines='80') or 'delete', stream='stdout'|'stderr'; an id
|
|
900
|
+
resolves only for this project and this session under the current access rules.
|
|
901
|
+
The echoed command is its first line; a multi-line command shows (N lines, M chars,
|
|
902
|
+
sha256). Under budget the output is complete: ANSI/control sequences stripped, each
|
|
903
|
+
line's \\r progress rewrites reduced to their final state, runs of 3+ identical
|
|
904
|
+
consecutive lines folded to one plus ` [x N]` (the header says `[collapsed …]` and the
|
|
905
|
+
raw streams are kept by id). Over budget, pytest/unittest/cargo/tsc/jest/vitest
|
|
906
|
+
failure blocks, error lines and totals are kept first (each announced by `[La-b: why]`),
|
|
907
|
+
then a bounded head/tail; a recognised runner past 30 lines gets a `--- summary ---`
|
|
908
|
+
(totals + one line per failing test). filter_output=False skips the two collapses so
|
|
909
|
+
every line comes through as written — escapes are still stripped, summaries and
|
|
910
|
+
priority regions still apply, and the cap is never lifted. Auto-logs git mutations
|
|
911
|
+
to the edit ledger.
|
|
893
912
|
Credentials: env_creds='NAME1,NAME2' injects vault entries as env vars, and
|
|
894
913
|
{{cred:NAME}} inside cmd expands server-side — decoded values never enter
|
|
895
|
-
model context (see c3_credentials; echoed values are auto-redacted
|
|
914
|
+
model context (see c3_credentials; echoed values are auto-redacted, in the
|
|
915
|
+
response and in the kept output).
|
|
896
916
|
Best-effort block of catastrophic commands (rm -rf of /, a top-level system dir, or
|
|
897
917
|
$HOME/~; fork bombs; whole-drive wipes) — a guard, NOT a sandbox. Soft-warns on
|
|
898
918
|
--force, --no-verify, reset --hard.
|
|
@@ -904,7 +924,10 @@ async def c3_shell(cmd: str, cwd: str = "", timeout: int = 60,
|
|
|
904
924
|
return _finalize_response(ctx, name, args, resp, summ, **kw)
|
|
905
925
|
|
|
906
926
|
return await handle_shell(cmd, cwd, timeout, filter_output, log, svc, finalize,
|
|
907
|
-
env_creds=env_creds
|
|
927
|
+
env_creds=env_creds, output_id=output_id,
|
|
928
|
+
output_action=output_action, pattern=pattern,
|
|
929
|
+
lines=lines or None, stream=stream or "stdout",
|
|
930
|
+
max_bytes=max_bytes or None)
|
|
908
931
|
|
|
909
932
|
|
|
910
933
|
@mcp.tool()
|
|
@@ -2,8 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
Wraps subprocess.Popen with the Windows-safe pattern from
|
|
4
4
|
services/edit_ledger.py::_git_combined (Popen + taskkill /F /T + stdin=DEVNULL).
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
Budgets and shapes the response (cli/tools/shell_render.py + shell_parsers.py:
|
|
6
|
+
normalised streams, runner-aware priority regions, omission only over budget),
|
|
7
|
+
auto-logs git mutations to the edit ledger, and accounts stdout tokens against
|
|
8
|
+
session budget.
|
|
7
9
|
|
|
8
10
|
Shell selection: on Windows, commands are run through Git Bash (bash.exe) when
|
|
9
11
|
it is available, so c3_shell speaks the same POSIX dialect as the native Bash
|
|
@@ -28,9 +30,31 @@ from pathlib import Path
|
|
|
28
30
|
from cli._shell_writes import shell_write_targets
|
|
29
31
|
from cli.tools import _grants
|
|
30
32
|
from cli.tools._helpers import finalize_with_tokens
|
|
31
|
-
from cli.tools.
|
|
33
|
+
from cli.tools.shell_parsers import (
|
|
34
|
+
SUMMARY_MIN_LINES,
|
|
35
|
+
detect_runner,
|
|
36
|
+
normalize_stream,
|
|
37
|
+
priority_regions,
|
|
38
|
+
structured_tail,
|
|
39
|
+
)
|
|
40
|
+
from cli.tools.shell_render import (
|
|
41
|
+
allocate,
|
|
42
|
+
cmd_display,
|
|
43
|
+
effective_budget,
|
|
44
|
+
grep_pattern,
|
|
45
|
+
human_bytes,
|
|
46
|
+
shape_stream,
|
|
47
|
+
split_lines,
|
|
48
|
+
split_preview,
|
|
49
|
+
)
|
|
32
50
|
from core import count_tokens
|
|
33
51
|
from services import access_guard
|
|
52
|
+
from services.shell_output import (
|
|
53
|
+
TEXT_MAX_BYTES,
|
|
54
|
+
OutputAccessError,
|
|
55
|
+
ShellCapture,
|
|
56
|
+
ShellOutputStore,
|
|
57
|
+
)
|
|
34
58
|
|
|
35
59
|
# Commands that mutate repo state — trigger edit-ledger refresh after success.
|
|
36
60
|
_GIT_MUTATING = re.compile(
|
|
@@ -211,9 +235,28 @@ def _kill_tree(proc: subprocess.Popen) -> None:
|
|
|
211
235
|
pass
|
|
212
236
|
|
|
213
237
|
|
|
238
|
+
def _default_redact(text: str) -> str:
|
|
239
|
+
"""Scrub vault values from a piece of output; never raises."""
|
|
240
|
+
try:
|
|
241
|
+
from services import credential_store as _creds
|
|
242
|
+
return _creds.redact_text(text)
|
|
243
|
+
except Exception:
|
|
244
|
+
return text
|
|
245
|
+
|
|
246
|
+
|
|
214
247
|
def _run_sync(cmd: str, cwd: str, timeout: int,
|
|
215
|
-
extra_env: dict | None = None
|
|
216
|
-
|
|
248
|
+
extra_env: dict | None = None, *, redact=_default_redact,
|
|
249
|
+
spool_dir=None) -> dict:
|
|
250
|
+
"""Blocking subprocess run with hard kill on timeout. Returns structured dict.
|
|
251
|
+
|
|
252
|
+
Since 2.112.0 the child's streams are not buffered in memory: a
|
|
253
|
+
ShellCapture pumps them to spool files with bounded head/tail previews
|
|
254
|
+
(services/shell_output.py). ``stdout``/``stderr`` in the result carry the
|
|
255
|
+
whole text when the stream is at most TEXT_MAX_BYTES and None otherwise;
|
|
256
|
+
``capture`` carries the stats and previews either way. Callers that
|
|
257
|
+
patch this function with a plain dict (tests) still work: no ``capture``
|
|
258
|
+
means "small output, text present".
|
|
259
|
+
"""
|
|
217
260
|
start = time.time()
|
|
218
261
|
bash = _select_bash()
|
|
219
262
|
if bash:
|
|
@@ -229,7 +272,6 @@ def _run_sync(cmd: str, cwd: str, timeout: int,
|
|
|
229
272
|
proc = subprocess.Popen(
|
|
230
273
|
popen_target, shell=use_shell, cwd=cwd,
|
|
231
274
|
stdout=subprocess.PIPE, stderr=subprocess.PIPE,
|
|
232
|
-
text=True, encoding="utf-8", errors="replace",
|
|
233
275
|
**_popen_kwargs(extra_env),
|
|
234
276
|
)
|
|
235
277
|
except (OSError, ValueError) as exc:
|
|
@@ -241,24 +283,27 @@ def _run_sync(cmd: str, cwd: str, timeout: int,
|
|
|
241
283
|
"timed_out": False,
|
|
242
284
|
"shell": shell_name,
|
|
243
285
|
}
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
286
|
+
if spool_dir is None:
|
|
287
|
+
spool_dir = ShellOutputStore().spool_dir()
|
|
288
|
+
capture = ShellCapture(proc, spool_dir, redact=redact, kill_tree=_kill_tree)
|
|
289
|
+
timed_out = capture.wait(timeout)
|
|
290
|
+
|
|
291
|
+
def _text(stream: str):
|
|
292
|
+
if getattr(capture.stats, stream).bytes > TEXT_MAX_BYTES:
|
|
293
|
+
return None
|
|
249
294
|
try:
|
|
250
|
-
|
|
295
|
+
return capture.text(stream)
|
|
251
296
|
except Exception:
|
|
252
|
-
|
|
253
|
-
timed_out = True
|
|
297
|
+
return None
|
|
254
298
|
|
|
255
299
|
return {
|
|
256
300
|
"exit_code": -1 if timed_out else (proc.returncode or 0),
|
|
257
|
-
"stdout": stdout
|
|
258
|
-
"stderr": stderr
|
|
259
|
-
"duration_ms": round((time.time() - start) * 1000),
|
|
301
|
+
"stdout": _text("stdout"),
|
|
302
|
+
"stderr": _text("stderr"),
|
|
303
|
+
"duration_ms": capture.duration_ms or round((time.time() - start) * 1000),
|
|
260
304
|
"timed_out": timed_out,
|
|
261
305
|
"shell": shell_name,
|
|
306
|
+
"capture": capture,
|
|
262
307
|
}
|
|
263
308
|
|
|
264
309
|
|
|
@@ -428,54 +473,195 @@ def _longest_line(*texts: str) -> int:
|
|
|
428
473
|
return longest
|
|
429
474
|
|
|
430
475
|
|
|
476
|
+
def _stream_facts(result: dict, stream: str) -> dict:
|
|
477
|
+
"""Size, line count, longest line and available text/previews of one stream."""
|
|
478
|
+
text = result.get(stream)
|
|
479
|
+
capture = result.get("capture")
|
|
480
|
+
if capture is not None:
|
|
481
|
+
st = getattr(capture.stats, stream)
|
|
482
|
+
return {"text": text, "head": st.head, "tail": st.tail, "bytes": st.bytes,
|
|
483
|
+
"lines": st.lines, "longest": st.longest_line}
|
|
484
|
+
text = text or ""
|
|
485
|
+
return {"text": text, "head": "", "tail": "", "bytes": len(text.encode("utf-8", errors="replace")),
|
|
486
|
+
"lines": text.count("\n") + (1 if text and not text.endswith("\n") else 0),
|
|
487
|
+
"longest": _longest_line(text)}
|
|
488
|
+
|
|
489
|
+
|
|
490
|
+
_ZERO_NORM = {"ansi_stripped": 0, "cr_collapsed": 0, "dup_collapsed": 0}
|
|
491
|
+
|
|
492
|
+
|
|
493
|
+
def _normalised(facts: dict, *, collapse: bool, fuzzy: bool) -> dict:
|
|
494
|
+
"""One stream after ``normalize_stream``: the text (or previews), its
|
|
495
|
+
logical lines in the index space ``shape_stream`` uses, the raw line
|
|
496
|
+
numbers of those lines when folding shifted them, and the counters."""
|
|
497
|
+
info = dict(_ZERO_NORM)
|
|
498
|
+
if facts["text"] is not None:
|
|
499
|
+
text, ni = normalize_stream(facts["text"], collapse=collapse, fuzzy_dups=fuzzy)
|
|
500
|
+
for k in _ZERO_NORM:
|
|
501
|
+
info[k] = ni[k]
|
|
502
|
+
return {"text": text, "head": "", "tail": "", "lines": split_lines(text),
|
|
503
|
+
"bytes": len(text.encode("utf-8", errors="replace")),
|
|
504
|
+
"total_lines": facts["lines"], "numbers": ni["line_numbers"],
|
|
505
|
+
"tail_numbers": None, "info": info}
|
|
506
|
+
head, hi = normalize_stream(facts["head"], collapse=collapse, fuzzy_dups=fuzzy)
|
|
507
|
+
tail, ti = normalize_stream(facts["tail"], collapse=collapse, fuzzy_dups=fuzzy)
|
|
508
|
+
for k in _ZERO_NORM:
|
|
509
|
+
info[k] = hi[k] + ti[k]
|
|
510
|
+
h_lines, t_lines, _torn = split_preview(head, tail)
|
|
511
|
+
return {"text": None, "head": head, "tail": tail, "lines": h_lines + t_lines,
|
|
512
|
+
"bytes": facts["bytes"], "total_lines": facts["lines"],
|
|
513
|
+
"numbers": hi["line_numbers"], "tail_numbers": ti["line_numbers"], "info": info}
|
|
514
|
+
|
|
515
|
+
|
|
516
|
+
def _region_line_count(regions) -> int:
|
|
517
|
+
seen: set[int] = set()
|
|
518
|
+
for a, b, _why in regions:
|
|
519
|
+
seen.update(range(a, b + 1))
|
|
520
|
+
return len(seen)
|
|
521
|
+
|
|
522
|
+
|
|
431
523
|
def render_shell_response(cmd: str, result: dict, svc, *,
|
|
432
524
|
filter_output: bool = True, warn: str = "",
|
|
433
525
|
capped_note: str = "", touched_files=(),
|
|
434
|
-
cred_names=(), swept_ghosts=()
|
|
526
|
+
cred_names=(), swept_ghosts=(),
|
|
527
|
+
max_bytes: int | None = None) -> tuple[str, dict]:
|
|
435
528
|
"""Turn a finished command into the body the agent reads, plus its stats.
|
|
436
529
|
|
|
437
530
|
Pure with respect to the subprocess: ``result`` is the dict _run_sync
|
|
438
|
-
returns (exit_code, stdout, stderr, duration_ms, timed_out, shell
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
531
|
+
returns (exit_code, stdout, stderr, duration_ms, timed_out, shell, and
|
|
532
|
+
since 2.112.0 an optional ``capture`` with stats and head/tail previews
|
|
533
|
+
for a stream too large to hold), so the shell-eval harness
|
|
534
|
+
(services/bench/shell_eval.py) can feed captured or synthetic streams
|
|
535
|
+
through exactly the code path a live call uses.
|
|
536
|
+
|
|
537
|
+
Budget (2.112.0, cli/tools/shell_render.py): the rendered body never
|
|
538
|
+
exceeds ``effective_budget()`` bytes — 18 KiB by default, 22 KiB ceiling,
|
|
539
|
+
``max_bytes`` and ``hybrid.shell_budget_bytes`` may only lower it,
|
|
540
|
+
``filter_output=False`` never lifts it.
|
|
541
|
+
|
|
542
|
+
Shaping (2.113.0, S2, cli/tools/shell_parsers.py) — the Cod rule: strip
|
|
543
|
+
ANSI and collapse ``\\r`` rewrites always, otherwise preserve complete
|
|
544
|
+
under-budget output, run the parsers always but omit only over budget:
|
|
545
|
+
|
|
546
|
+
1. Both streams are normalised: ``\\r\\n`` → ``\\n``, ANSI escape and
|
|
547
|
+
control sequences stripped (not a loss), each line's ``\\r``
|
|
548
|
+
progress rewrites collapsed to the final state, runs of three or
|
|
549
|
+
more identical consecutive lines folded to the first plus
|
|
550
|
+
`` [x N]``. The last two are a loss: the header says
|
|
551
|
+
``[collapsed …]``, ``stats["filtered"]`` is set and the raw streams
|
|
552
|
+
are spilled. ``filter_output=False`` skips the two collapses (ANSI
|
|
553
|
+
is always stripped) and, as before, never lifts the byte cap.
|
|
554
|
+
2. The runner is detected (pytest, unittest, cargo/rustc, tsc, jest,
|
|
555
|
+
vitest) and its priority regions computed on every call; a stream
|
|
556
|
+
that fits its allocation passes through whole regardless. A stream
|
|
557
|
+
that does not is re-normalised with the duplicate test widened to
|
|
558
|
+
lines differing only in digits / hex / timestamps, then shaped:
|
|
559
|
+
priority regions first (each announced by ``[La-b: why]`` when not
|
|
560
|
+
contiguous), head/tail with the rest, one omission note naming the
|
|
561
|
+
output id. Unrecognised output uses generic error anchors, capped at
|
|
562
|
+
60% of the allocation so head and tail always keep something.
|
|
563
|
+
3. For a recognised runner with more than SUMMARY_MIN_LINES lines a
|
|
564
|
+
``--- summary ---`` section (totals + one line per failing test,
|
|
565
|
+
cap 20) is appended and counted inside the budget.
|
|
566
|
+
|
|
567
|
+
The legacy ``>30 newlines → handle_filter`` path is gone from this
|
|
568
|
+
function (``c3_filter`` the tool is untouched). Whenever anything was
|
|
569
|
+
dropped — collapsed, clipped or windowed — ``stats["needs_spill"]``
|
|
570
|
+
tells handle_shell to keep the raw streams.
|
|
444
571
|
|
|
445
572
|
``stats`` is what telemetry records about the call (see
|
|
446
573
|
SessionManager.record_tool_tokens ``detail``): stdout_bytes and
|
|
447
|
-
stderr_bytes are measured
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
574
|
+
stderr_bytes are measured on the RAW streams; longest_line is the tell
|
|
575
|
+
for the single-line monsters (minified bundles, JSONL) that a
|
|
576
|
+
newline-count trigger never sees; filtered (a lossy collapse happened),
|
|
577
|
+
spilled, output_id, runner, ansi_stripped, cr_collapsed, dup_collapsed
|
|
578
|
+
and priority_lines (lines the parsers marked, both streams) describe
|
|
579
|
+
what this renderer did.
|
|
451
580
|
"""
|
|
452
|
-
|
|
453
|
-
|
|
581
|
+
out = _stream_facts(result, "stdout")
|
|
582
|
+
err = _stream_facts(result, "stderr")
|
|
583
|
+
capture = result.get("capture")
|
|
454
584
|
stats: dict = {
|
|
455
585
|
"exit_code": result.get("exit_code"),
|
|
456
586
|
"timed_out": bool(result.get("timed_out")),
|
|
457
|
-
"stdout_bytes":
|
|
458
|
-
"stderr_bytes":
|
|
459
|
-
"longest_line":
|
|
587
|
+
"stdout_bytes": out["bytes"],
|
|
588
|
+
"stderr_bytes": err["bytes"],
|
|
589
|
+
"longest_line": max(out["longest"], err["longest"]),
|
|
460
590
|
"filtered": False,
|
|
461
591
|
"spilled": False,
|
|
462
592
|
"output_id": None,
|
|
463
593
|
"cmd_class": _cmd_class(cmd),
|
|
594
|
+
"needs_spill": False,
|
|
595
|
+
"runner": None,
|
|
596
|
+
"ansi_stripped": 0,
|
|
597
|
+
"cr_collapsed": 0,
|
|
598
|
+
"dup_collapsed": 0,
|
|
599
|
+
"priority_lines": 0,
|
|
464
600
|
}
|
|
465
601
|
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
602
|
+
config_default = None
|
|
603
|
+
try:
|
|
604
|
+
config_default = (getattr(svc, "hybrid_config", None) or {}).get("shell_budget_bytes")
|
|
605
|
+
except Exception:
|
|
606
|
+
config_default = None
|
|
607
|
+
budget = effective_budget(max_bytes, config_default=config_default)
|
|
608
|
+
stats["budget_bytes"] = budget
|
|
609
|
+
output_id = getattr(capture, "output_id", None) if capture is not None else None
|
|
610
|
+
focus = grep_pattern(cmd)
|
|
611
|
+
collapse = bool(filter_output)
|
|
612
|
+
|
|
613
|
+
# 1. Normalise. A stream with previews only (over TEXT_MAX_BYTES) is over
|
|
614
|
+
# budget by definition, so it gets the widened duplicate test at once.
|
|
615
|
+
norm_out = _normalised(out, collapse=collapse, fuzzy=out["text"] is None)
|
|
616
|
+
norm_err = _normalised(err, collapse=collapse, fuzzy=err["text"] is None)
|
|
617
|
+
|
|
618
|
+
# 2. Runner, summary, allocation. The summary is measured first so the
|
|
619
|
+
# streams are allocated what is left of the budget.
|
|
620
|
+
runner = detect_runner(cmd, norm_out["text"] or norm_out["head"] + norm_out["tail"],
|
|
621
|
+
norm_err["text"] or norm_err["head"] + norm_err["tail"])
|
|
622
|
+
stats["runner"] = runner
|
|
623
|
+
summary = ""
|
|
624
|
+
if runner and (out["lines"] + err["lines"]) > SUMMARY_MIN_LINES:
|
|
625
|
+
summary = structured_tail(runner, norm_out["lines"] + norm_err["lines"], result.get("exit_code"))
|
|
626
|
+
summary_bytes = len(summary.encode("utf-8", errors="replace"))
|
|
627
|
+
out_alloc, err_alloc = allocate(budget - summary_bytes, norm_out["bytes"], norm_err["bytes"])
|
|
628
|
+
|
|
629
|
+
# 3. A stream that does not fit is re-normalised with fuzzy duplicates,
|
|
630
|
+
# then shaped around its priority regions.
|
|
631
|
+
if collapse and norm_out["text"] is not None and norm_out["bytes"] > out_alloc:
|
|
632
|
+
norm_out = _normalised(out, collapse=True, fuzzy=True)
|
|
633
|
+
if collapse and norm_err["text"] is not None and norm_err["bytes"] > err_alloc:
|
|
634
|
+
norm_err = _normalised(err, collapse=True, fuzzy=True)
|
|
635
|
+
for key in ("ansi_stripped", "cr_collapsed", "dup_collapsed"):
|
|
636
|
+
stats[key] = norm_out["info"][key] + norm_err["info"][key]
|
|
637
|
+
stats["filtered"] = bool(stats["cr_collapsed"] or stats["dup_collapsed"])
|
|
638
|
+
|
|
639
|
+
prio_out = priority_regions(runner, norm_out["lines"]) if norm_out["lines"] else []
|
|
640
|
+
prio_err = priority_regions(runner, norm_err["lines"]) if norm_err["lines"] else []
|
|
641
|
+
stats["priority_lines"] = _region_line_count(prio_out) + _region_line_count(prio_err)
|
|
642
|
+
share = 1.0 if runner else 0.6
|
|
643
|
+
|
|
644
|
+
shaped_out, info_out = shape_stream(
|
|
645
|
+
full_text=norm_out["text"], head=norm_out["head"], tail=norm_out["tail"],
|
|
646
|
+
total_bytes=norm_out["bytes"], total_lines=norm_out["total_lines"], alloc=out_alloc,
|
|
647
|
+
output_id=output_id, focus=focus, priority=prio_out, priority_share=share,
|
|
648
|
+
line_numbers=norm_out["numbers"], tail_line_numbers=norm_out["tail_numbers"])
|
|
649
|
+
if err["bytes"] > 0 or (err["text"] or "").strip():
|
|
650
|
+
shaped_err, info_err = shape_stream(
|
|
651
|
+
full_text=norm_err["text"], head=norm_err["head"], tail=norm_err["tail"],
|
|
652
|
+
total_bytes=norm_err["bytes"], total_lines=norm_err["total_lines"], alloc=err_alloc,
|
|
653
|
+
output_id=output_id, focus=focus, priority=prio_err, priority_share=share,
|
|
654
|
+
line_numbers=norm_err["numbers"], tail_line_numbers=norm_err["tail_numbers"])
|
|
655
|
+
else:
|
|
656
|
+
shaped_err, info_err = "", {"cut": False, "omitted_lines": 0, "omitted_bytes": 0,
|
|
657
|
+
"clipped_lines": 0, "rendered_bytes": 0, "priority_kept": 0}
|
|
658
|
+
|
|
659
|
+
cut = bool(info_out["cut"] or info_err["cut"])
|
|
660
|
+
stats["needs_spill"] = bool(stats["filtered"] or cut)
|
|
661
|
+
stats["spilled"] = bool(stats["needs_spill"] and output_id)
|
|
662
|
+
stats["output_id"] = output_id if stats["spilled"] else None
|
|
663
|
+
stats["omitted_lines"] = info_out["omitted_lines"] + info_err["omitted_lines"]
|
|
664
|
+
stats["clipped_lines"] = info_out["clipped_lines"] + info_err["clipped_lines"]
|
|
479
665
|
|
|
480
666
|
if result.get("timed_out"):
|
|
481
667
|
status = "TIMEOUT"
|
|
@@ -484,14 +670,30 @@ def render_shell_response(cmd: str, result: dict, svc, *,
|
|
|
484
670
|
else:
|
|
485
671
|
status = f"FAIL({result.get('exit_code')})"
|
|
486
672
|
|
|
673
|
+
collapsed_note = ""
|
|
674
|
+
if stats["filtered"]:
|
|
675
|
+
parts = []
|
|
676
|
+
if stats["cr_collapsed"]:
|
|
677
|
+
parts.append(f"{stats['cr_collapsed']} cr rewrites")
|
|
678
|
+
if stats["dup_collapsed"]:
|
|
679
|
+
parts.append(f"{stats['dup_collapsed']} dup lines")
|
|
680
|
+
collapsed_note = f" [collapsed {', '.join(parts)}]"
|
|
681
|
+
size_note = ""
|
|
682
|
+
if cut or stats["spilled"]:
|
|
683
|
+
size_note = (f" (stdout {human_bytes(out['bytes'])}/{out['lines']} lines,"
|
|
684
|
+
f" stderr {human_bytes(err['bytes'])}/{err['lines']} lines,")
|
|
685
|
+
size_note += f" output_id={output_id})" if stats["spilled"] else " not spilled)"
|
|
686
|
+
|
|
487
687
|
body = (
|
|
488
688
|
f"{warn}{capped_note}"
|
|
489
|
-
f"[c3_shell:{status}] {result.get('duration_ms', 0)}ms{
|
|
490
|
-
f"$ {cmd}\n"
|
|
491
|
-
f"--- stdout ---\n{
|
|
689
|
+
f"[c3_shell:{status}] {result.get('duration_ms', 0)}ms{collapsed_note}{size_note}\n"
|
|
690
|
+
f"$ {cmd_display(cmd)}\n"
|
|
691
|
+
f"--- stdout ---\n{shaped_out.rstrip()}\n"
|
|
492
692
|
)
|
|
493
|
-
if
|
|
494
|
-
body += f"--- stderr ---\n{
|
|
693
|
+
if shaped_err.strip():
|
|
694
|
+
body += f"--- stderr ---\n{shaped_err.rstrip()}\n"
|
|
695
|
+
if summary:
|
|
696
|
+
body += summary
|
|
495
697
|
dependency_hint = _dependency_hint(cmd, result)
|
|
496
698
|
if dependency_hint:
|
|
497
699
|
body += f"--- hint ---\n{dependency_hint}\n"
|
|
@@ -724,9 +926,102 @@ def _shell_warn_grant(svc, work_cwd: str) -> str | None:
|
|
|
724
926
|
return None
|
|
725
927
|
|
|
726
928
|
|
|
929
|
+
_OUTPUT_ACTIONS = ("read", "search", "tail", "delete")
|
|
930
|
+
|
|
931
|
+
|
|
932
|
+
def _handle_output(output_id: str, action: str, pattern: str, lines, stream: str,
|
|
933
|
+
max_bytes, svc, finalize) -> str:
|
|
934
|
+
"""Page a spilled output back by id (2.112.0).
|
|
935
|
+
|
|
936
|
+
The id is resolved for THIS project and THIS host session under the
|
|
937
|
+
CURRENT Access Guard rules — services/shell_output.py documents why a
|
|
938
|
+
spill from a more privileged call must not be readable by a later, less
|
|
939
|
+
privileged one. Every read is re-budgeted like a live response.
|
|
940
|
+
"""
|
|
941
|
+
action = (action or "read").strip().lower()
|
|
942
|
+
if action not in _OUTPUT_ACTIONS:
|
|
943
|
+
return (f"[c3_shell:error] output_action must be one of {', '.join(_OUTPUT_ACTIONS)}; "
|
|
944
|
+
f"got {action!r}")
|
|
945
|
+
stream = (stream or "stdout").strip().lower()
|
|
946
|
+
if stream not in ("stdout", "stderr"):
|
|
947
|
+
return "[c3_shell:error] stream must be 'stdout' or 'stderr'"
|
|
948
|
+
project_path = str(svc.project_path)
|
|
949
|
+
|
|
950
|
+
def guard_check(path: str):
|
|
951
|
+
try:
|
|
952
|
+
return access_guard.check(path, "read", project_path)
|
|
953
|
+
except Exception as exc: # evaluator error fails closed
|
|
954
|
+
return access_guard.Denial("<evaluator-error>", "deny", "builtin",
|
|
955
|
+
f"evaluator error: {type(exc).__name__}")
|
|
956
|
+
|
|
957
|
+
store = ShellOutputStore()
|
|
958
|
+
try:
|
|
959
|
+
meta = store.resolve(output_id, project_path=project_path,
|
|
960
|
+
session_id=_grants.session_id(svc), guard_check=guard_check)
|
|
961
|
+
except OutputAccessError as exc:
|
|
962
|
+
return f"[c3_shell:error] {exc}"
|
|
963
|
+
config_default = None
|
|
964
|
+
try:
|
|
965
|
+
config_default = (getattr(svc, "hybrid_config", None) or {}).get("shell_budget_bytes")
|
|
966
|
+
except Exception:
|
|
967
|
+
pass
|
|
968
|
+
budget = effective_budget(max_bytes, config_default=config_default) - 512
|
|
969
|
+
facts = getattr(meta, stream) or {}
|
|
970
|
+
header = (f"[c3_shell:output] {meta.id} {action} {stream} · $ {meta.cmd_display} · "
|
|
971
|
+
f"exit {meta.exit_code}{' (timed out)' if meta.timed_out else ''} · "
|
|
972
|
+
f"{human_bytes(facts.get('bytes', 0))}/{facts.get('lines', 0)} lines · "
|
|
973
|
+
f"captured {meta.created_at[:19]}\n")
|
|
974
|
+
try:
|
|
975
|
+
if action == "delete":
|
|
976
|
+
store.delete(meta)
|
|
977
|
+
body = header + "deleted\n"
|
|
978
|
+
elif action == "search":
|
|
979
|
+
if not pattern:
|
|
980
|
+
return "[c3_shell:error] output_action='search' needs a pattern"
|
|
981
|
+
body = header + store.search(meta, pattern, stream, max_bytes=budget)
|
|
982
|
+
elif action == "tail":
|
|
983
|
+
n = 50
|
|
984
|
+
if isinstance(lines, int) and lines > 0:
|
|
985
|
+
n = lines
|
|
986
|
+
body = header + store.tail(meta, stream, lines=n, max_bytes=budget)
|
|
987
|
+
else:
|
|
988
|
+
window = None
|
|
989
|
+
if isinstance(lines, (list, tuple)) and len(lines) == 2:
|
|
990
|
+
window = (int(lines[0]), int(lines[1]))
|
|
991
|
+
elif isinstance(lines, int) and lines > 0:
|
|
992
|
+
window = (lines, lines)
|
|
993
|
+
elif isinstance(lines, str) and lines.strip():
|
|
994
|
+
parts = [p for p in re.split(r"[,\-:\s]+", lines.strip()) if p]
|
|
995
|
+
if len(parts) == 1:
|
|
996
|
+
window = (int(parts[0]), int(parts[0]))
|
|
997
|
+
elif len(parts) >= 2:
|
|
998
|
+
window = (int(parts[0]), int(parts[1]))
|
|
999
|
+
body = header + store.read(meta, stream, lines=window, max_bytes=budget)
|
|
1000
|
+
except (ValueError, re.error) as exc:
|
|
1001
|
+
return f"[c3_shell:error] {exc}"
|
|
1002
|
+
if not body.endswith("\n"):
|
|
1003
|
+
body += "\n"
|
|
1004
|
+
return finalize_with_tokens(
|
|
1005
|
+
finalize, svc, "c3_shell",
|
|
1006
|
+
{"output_id": output_id, "output_action": action},
|
|
1007
|
+
body, f"shell output {action} {output_id}",
|
|
1008
|
+
detail={"cmd_class": "output", "output_id": output_id, "output_action": action,
|
|
1009
|
+
"response_bytes": len(body.encode("utf-8", errors="replace")),
|
|
1010
|
+
"response_tokens": count_tokens(body)},
|
|
1011
|
+
response_tokens=count_tokens(body),
|
|
1012
|
+
)
|
|
1013
|
+
|
|
1014
|
+
|
|
727
1015
|
async def handle_shell(cmd: str, cwd: str, timeout: int, filter_output: bool,
|
|
728
1016
|
log: bool, svc, finalize, env_creds: str = "",
|
|
729
|
-
enable_creds: bool = True
|
|
1017
|
+
enable_creds: bool = True, *, output_id: str = "",
|
|
1018
|
+
output_action: str = "", pattern: str = "",
|
|
1019
|
+
lines=None, stream: str = "stdout",
|
|
1020
|
+
max_bytes: int | None = None) -> str:
|
|
1021
|
+
if output_id:
|
|
1022
|
+
return await asyncio.to_thread(
|
|
1023
|
+
_handle_output, output_id, output_action, pattern, lines, stream,
|
|
1024
|
+
max_bytes, svc, finalize)
|
|
730
1025
|
if not cmd or not cmd.strip():
|
|
731
1026
|
return "[c3_shell:error] empty command"
|
|
732
1027
|
# _BLOCKED never consults grants — no approval flow reaches the
|
|
@@ -860,16 +1155,23 @@ async def handle_shell(cmd: str, cwd: str, timeout: int, filter_output: bool,
|
|
|
860
1155
|
else None
|
|
861
1156
|
)
|
|
862
1157
|
|
|
1158
|
+
# Decoded values a child process may echo (env dumps, set, crash output)
|
|
1159
|
+
# are scrubbed IN THE STREAM by _run_sync's redactor, before a byte
|
|
1160
|
+
# reaches the spool or any preview, so neither the response nor a spill
|
|
1161
|
+
# ever holds one.
|
|
863
1162
|
result = await asyncio.to_thread(
|
|
864
1163
|
_run_sync, exec_cmd, work_cwd, timeout, extra_env or None)
|
|
1164
|
+
capture = result.get("capture")
|
|
865
1165
|
|
|
866
1166
|
swept_ghosts = _sweep_new_ghost_files(ghost_root, _ghosts_before)
|
|
867
1167
|
|
|
868
|
-
#
|
|
869
|
-
#
|
|
1168
|
+
# Belt over the in-stream scrub for the small-output text (and for a
|
|
1169
|
+
# result a test handed in without a capture).
|
|
870
1170
|
if enable_creds:
|
|
871
|
-
result
|
|
872
|
-
|
|
1171
|
+
if result.get("stdout") is not None:
|
|
1172
|
+
result["stdout"] = _creds.redact_text(result["stdout"])
|
|
1173
|
+
if result.get("stderr") is not None:
|
|
1174
|
+
result["stderr"] = _creds.redact_text(result["stderr"])
|
|
873
1175
|
if cred_names:
|
|
874
1176
|
# Usage state is keyed by entry NAME; collapse dotted field refs.
|
|
875
1177
|
_creds.touch_last_used(
|
|
@@ -936,12 +1238,45 @@ async def handle_shell(cmd: str, cwd: str, timeout: int, filter_output: bool,
|
|
|
936
1238
|
f"run_in_background, which is not bound by this limit.\n"
|
|
937
1239
|
)
|
|
938
1240
|
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
1241
|
+
try:
|
|
1242
|
+
body, stats = await asyncio.to_thread(
|
|
1243
|
+
render_shell_response, cmd, result, svc,
|
|
1244
|
+
filter_output=filter_output, warn=warn, capped_note=capped_note,
|
|
1245
|
+
touched_files=touched_files, cred_names=cred_names,
|
|
1246
|
+
swept_ghosts=swept_ghosts, max_bytes=max_bytes,
|
|
1247
|
+
)
|
|
1248
|
+
# Keep the raw streams only when the body dropped something: the
|
|
1249
|
+
# spill is what makes a clipped or filtered response recoverable
|
|
1250
|
+
# without re-running the command (docs/shell-output.md).
|
|
1251
|
+
if capture is not None:
|
|
1252
|
+
if stats.get("needs_spill"):
|
|
1253
|
+
try:
|
|
1254
|
+
ShellOutputStore().promote(
|
|
1255
|
+
capture, project_path=str(svc.project_path),
|
|
1256
|
+
session_id=_grants.session_id(svc), cmd=cmd, cwd=work_cwd,
|
|
1257
|
+
guard_paths=_scan_candidates(cmd, work_cwd),
|
|
1258
|
+
exit_code=result.get("exit_code", -1),
|
|
1259
|
+
timed_out=bool(result.get("timed_out")),
|
|
1260
|
+
duration_ms=result.get("duration_ms", 0))
|
|
1261
|
+
except Exception as exc:
|
|
1262
|
+
stats["spilled"] = False
|
|
1263
|
+
stats["output_id"] = None
|
|
1264
|
+
body += (f"[c3_shell:note] the raw output could not be kept "
|
|
1265
|
+
f"({type(exc).__name__}: {exc}); the output id above is not retrievable\n")
|
|
1266
|
+
try:
|
|
1267
|
+
capture.discard()
|
|
1268
|
+
except Exception:
|
|
1269
|
+
pass
|
|
1270
|
+
else:
|
|
1271
|
+
capture.discard()
|
|
1272
|
+
except Exception:
|
|
1273
|
+
if capture is not None:
|
|
1274
|
+
try:
|
|
1275
|
+
capture.discard()
|
|
1276
|
+
except Exception:
|
|
1277
|
+
pass
|
|
1278
|
+
raise
|
|
1279
|
+
stats.pop("needs_spill", None)
|
|
945
1280
|
|
|
946
1281
|
if result["timed_out"]:
|
|
947
1282
|
status = "TIMEOUT"
|