code-context-control 2.111.0__tar.gz → 2.112.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.112.0}/PKG-INFO +1 -1
- {code_context_control-2.111.0 → code_context_control-2.112.0}/cli/c3.py +1 -1
- {code_context_control-2.111.0 → code_context_control-2.112.0}/cli/mcp_server.py +20 -5
- {code_context_control-2.111.0 → code_context_control-2.112.0}/cli/tools/shell.py +292 -51
- code_context_control-2.112.0/cli/tools/shell_render.py +351 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/code_context_control.egg-info/PKG-INFO +1 -1
- {code_context_control-2.111.0 → code_context_control-2.112.0}/code_context_control.egg-info/SOURCES.txt +4 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/pyproject.toml +1 -1
- code_context_control-2.112.0/services/shell_output.py +1051 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_c3_shell.py +14 -1
- code_context_control-2.112.0/tests/test_shell_budget_s1.py +317 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_shell_eval.py +2 -1
- code_context_control-2.112.0/tests/test_shell_output.py +727 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/LICENSE +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/README.md +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/cli/__init__.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/cli/_hook_utils.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/cli/_shell_writes.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/cli/commands/__init__.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/cli/commands/common.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/cli/commands/parser.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/cli/docs.html +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/cli/edits.html +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/cli/guide/access.html +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/cli/guide/bitbucket.html +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/cli/guide/credentials.html +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/cli/guide/getting-started.html +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/cli/guide/index.html +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/cli/guide/masking.html +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/cli/guide/oracle.html +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/cli/guide/shared.css +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/cli/guide/tools.html +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/cli/guide/workflow.html +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/cli/hook_access_guard.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/cli/hook_artifact.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/cli/hook_auto_snapshot.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/cli/hook_c3_signal.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/cli/hook_c3read.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/cli/hook_dispatch.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/cli/hook_edit_ledger.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/cli/hook_edit_unlock.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/cli/hook_filter.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/cli/hook_ghost_files.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/cli/hook_pretool_enforce.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/cli/hook_prompt_recall.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/cli/hook_read.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/cli/hook_session_stats.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/cli/hook_terse_advisor.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/cli/hub_server.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/cli/hub_ui/app.js +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/cli/hub_ui/components/add_project.js +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/cli/hub_ui/components/config_editor.js +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/cli/hub_ui/components/drill_artifacts.js +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/cli/hub_ui/components/drill_health.js +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/cli/hub_ui/components/drill_panel.js +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/cli/hub_ui/components/drill_subprojects.js +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/cli/hub_ui/components/drill_tasks.js +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/cli/hub_ui/components/drill_views.js +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/cli/hub_ui/components/global_search.js +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/cli/hub_ui/components/hub_access.js +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/cli/hub_ui/components/hub_ci.js +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/cli/hub_ui/components/hub_cred_audit.js +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/cli/hub_ui/components/hub_credentials.js +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/cli/hub_ui/components/hub_enforcement.js +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/cli/hub_ui/components/hub_locks.js +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/cli/hub_ui/components/hub_tokens.js +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/cli/hub_ui/components/mcp_manager.js +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/cli/hub_ui/components/modals.js +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/cli/hub_ui/components/project_card.js +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/cli/hub_ui/components/project_tree.js +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/cli/hub_ui/components/session_drawer.js +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/cli/hub_ui/components/settings_modal.js +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/cli/hub_ui/components/sidebar.js +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/cli/hub_ui/components/summary_bar.js +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/cli/hub_ui/components/task_board.js +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/cli/hub_ui/components/toasts.js +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/cli/hub_ui/components/topbar.js +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/cli/hub_ui/state.js +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/cli/hub_ui.html +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/cli/mcp_proxy.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/cli/progress.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/cli/server.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/cli/tools/__init__.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/cli/tools/_grants.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/cli/tools/_helpers.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/cli/tools/agent.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/cli/tools/artifacts.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/cli/tools/bitbucket.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/cli/tools/ci.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/cli/tools/compress.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/cli/tools/credentials.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/cli/tools/delegate.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/cli/tools/edit.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/cli/tools/edit_verify.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/cli/tools/edits.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/cli/tools/federate.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/cli/tools/filter.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/cli/tools/impact.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/cli/tools/jira.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/cli/tools/locks.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/cli/tools/memory.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/cli/tools/override.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/cli/tools/project.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/cli/tools/read.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/cli/tools/search.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/cli/tools/session.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/cli/tools/status.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/cli/tools/tasks.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/cli/tools/validate.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/cli/ui/api.js +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/cli/ui/app.js +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/cli/ui/components/access.js +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/cli/ui/components/bitbucket.js +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/cli/ui/components/chat.js +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/cli/ui/components/credentials.js +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/cli/ui/components/dashboard.js +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/cli/ui/components/edits.js +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/cli/ui/components/enforcement.js +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/cli/ui/components/instructions.js +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/cli/ui/components/jira.js +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/cli/ui/components/memory.js +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/cli/ui/components/sessions.js +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/cli/ui/components/settings.js +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/cli/ui/components/sidebar.js +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/cli/ui/components/tasks.js +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/cli/ui/icons.js +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/cli/ui/pm_shared.js +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/cli/ui/shared.js +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/cli/ui/theme.js +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/cli/ui.html +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/cli/ui_legacy.html +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/cli/ui_nano.html +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/code_context_control.egg-info/dependency_links.txt +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/code_context_control.egg-info/entry_points.txt +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/code_context_control.egg-info/requires.txt +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/code_context_control.egg-info/top_level.txt +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/core/__init__.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/core/config.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/core/ide.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/core/mcp_toml.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/core/web_security.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/oracle/__init__.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/oracle/config.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/oracle/mcp_oracle.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/oracle/oracle_server.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/oracle/oracle_ui.html +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/oracle/services/__init__.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/oracle/services/activity_reporter.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/oracle/services/api_auth.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/oracle/services/c3_bridge.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/oracle/services/chat_engine.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/oracle/services/chat_poll.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/oracle/services/chat_store.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/oracle/services/cross_memory.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/oracle/services/discovery_audit.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/oracle/services/federated_graph.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/oracle/services/health_checker.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/oracle/services/insight_engine.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/oracle/services/local_session.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/oracle/services/memory_reader.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/oracle/services/memory_writer.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/oracle/services/mobile_api.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/oracle/services/project_scanner.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/oracle/services/review_agent.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/oracle/services/tool_executor.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/oracle/services/tool_registry.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/oracle/ui/activity.js +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/oracle/ui/agents.js +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/oracle/ui/app.js +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/oracle/ui/busy.js +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/oracle/ui/chat/conversations.js +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/oracle/ui/chat/input.js +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/oracle/ui/chat/markdown.js +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/oracle/ui/chat/send.js +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/oracle/ui/chat/stream_renderer.js +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/oracle/ui/chat/toolbar.js +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/oracle/ui/core.js +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/oracle/ui/crossgraph.js +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/oracle/ui/header.js +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/oracle/ui/insights.js +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/oracle/ui/projects.js +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/oracle/ui/qrcode.js +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/oracle/ui/settings.js +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/oracle/ui/suggestions.js +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/oracle/ui/theme_tabs.js +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/services/__init__.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/services/access_guard.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/services/access_telemetry.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/services/activity_log.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/services/agent_base.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/services/agent_locks.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/services/agents.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/services/artifact_defs.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/services/artifact_store.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/services/auto_memory.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/services/background_service.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/services/bench/__init__.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/services/bench/external/__init__.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/services/bench/external/aider_polyglot.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/services/bench/external/swe_bench.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/services/bench/search_eval.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/services/bench/shell_eval.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/services/benchmark_dashboard.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/services/bitbucket_client.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/services/bitbucket_credentials.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/services/ci_act.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/services/ci_cache.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/services/ci_expr.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/services/ci_failures.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/services/ci_github.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/services/ci_impact.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/services/ci_intel.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/services/ci_runner.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/services/ci_workflow.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/services/circuit_breaker.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/services/claude_md.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/services/compressor.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/services/context_snapshot.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/services/conversation_store.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/services/cred_audit.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/services/cred_telemetry.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/services/credential_store.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/services/doc_index.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/services/e2e_benchmark.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/services/e2e_evaluator.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/services/e2e_tasks.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/services/edit_ledger.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/services/embedding_index.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/services/enforcement_policy.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/services/error_reporting.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/services/file_memory.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/services/git_context.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/services/hub_service.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/services/index_store.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/services/indexer.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/services/jira_client.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/services/jira_cloud.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/services/jira_credentials.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/services/jira_data_center.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/services/jira_links.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/services/lexical_index.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/services/mask_activation.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/services/mask_mirror.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/services/mask_presets.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/services/memory.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/services/memory_consolidator.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/services/memory_distiller.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/services/memory_graph.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/services/memory_grounder.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/services/memory_queue.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/services/memory_scorer.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/services/metrics.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/services/notifications.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/services/ollama_bridge.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/services/ollama_client.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/services/ollama_credentials.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/services/oracle_service.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/services/output_filter.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/services/override_grants.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/services/override_policy.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/services/override_requests.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/services/override_wake.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/services/parser.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/services/project_manager.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/services/project_runtime.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/services/protocol.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/services/proxy_state.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/services/repo_map.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/services/repo_shape.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/services/reranker.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/services/retention.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/services/retrieval.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/services/retrieval_broker.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/services/router.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/services/runtime.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/services/scanner.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/services/session_benchmark.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/services/session_manager.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/services/session_preloader.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/services/subprojects.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/services/task_store.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/services/telemetry.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/services/text_index.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/services/time_tracker.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/services/tool_classifier.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/services/transcript_index.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/services/validation_cache.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/services/vector_store.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/services/watcher.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/services/win_subprocess.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/setup.cfg +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_access_builtin_optout.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_access_guard.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_access_guard_meta.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_access_guard_shell_project.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_access_guard_surfaces.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_access_guard_wiring.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_activity_reporter.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_agent_locks.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_aider_polyglot.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_antigravity_transition.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_artifact_store.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_artifact_tool.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_background_service.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_bitbucket_cli_smoke.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_bitbucket_client.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_bitbucket_config_fallback.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_bitbucket_credentials.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_bitbucket_tool.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_builtin_modes.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_c3_bridge_project_artifacts.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_chat_poll.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_ci_act.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_ci_cache.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_ci_expr.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_ci_impact.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_ci_intel.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_ci_runner.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_ci_workflow.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_circuit_breaker.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_claude_md_merge.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_claude_md_updater.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_cli_smoke.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_compressor_large_file.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_confirm_guard.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_confirm_guard_wiring.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_cooccurrence_bounds.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_cred_audit.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_cred_telemetry.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_credential_login_kind.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_credential_store.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_credential_ui_parity.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_credentials_routes.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_credentials_tool.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_creds_cli_smoke.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_delegate_cascade.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_delegate_version_probe.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_e2e_benchmark.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_edit_ledger_deadline.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_edit_ledger_hook.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_edit_locking.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_edit_normalization.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_edit_verify.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_embedding_index_deadlock.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_enforcement_flip.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_enforcement_policy.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_enforcement_routes.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_env_parser.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_failed_calls_do_not_unlock.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_federated_graph.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_filter_backoff.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_ghost_files.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_ghost_generation.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_git_branch_awareness.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_hook_access_guard.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_hook_codex_compat.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_hook_dispatch.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_hook_pretool_enforce.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_hook_prompt_recall.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_hook_smoke.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_hook_state.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_hook_utf8_stdio.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_hub_credentials_route.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_hub_credentials_routes_write.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_hub_enforcement_routes.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_hub_inspect_api.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_hub_locks_routes.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_hub_oracle_service_routes.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_hub_override_routes.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_hub_server_smoke.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_hub_subproject_links.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_ide_workflow_adaptation.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_index_cap_not_hardcoded.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_init_clear_preserves_user_content.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_init_scan.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_install_mcp_entrypoint.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_jira_cli_smoke.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_jira_client.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_jira_config_fallback.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_jira_credentials.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_jira_links.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_jira_routes.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_jira_tool.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_lazy_store_init.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_mask_guard.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_mask_routes.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_mask_surfaces.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_mcp_host_guard.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_mcp_memory_timeout.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_mcp_server_smoke.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_mcp_toml.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_memory_distiller.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_memory_graph_api.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_memory_queue.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_memory_system.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_mobile_api.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_mobile_extras.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_mobile_override_routes.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_mobile_security_api.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_no_stale_model_pins.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_notification_dedup.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_notification_discipline.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_ollama_credentials.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_oracle_api_auth.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_oracle_apikey_api.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_oracle_c3_bridge.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_oracle_chat_engine.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_oracle_chat_store.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_oracle_discovery_api.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_oracle_discovery_audit.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_oracle_health_probe.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_oracle_local_auth.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_oracle_ollama_bridge.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_oracle_scanner_cache.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_oracle_security_fixes.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_oracle_session_bootstrap.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_oracle_subproject_awareness.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_oracle_ui_bundle.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_output_filter.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_override_grants.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_override_grants_mcp.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_override_requests.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_override_wake.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_permissions.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_pm_api.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_project_manager.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_project_manager_merge.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_project_tool.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_read_coercion.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_read_edit_parity.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_related_facts.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_repo_map.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_repo_shape.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_response_boilerplate.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_retention.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_review_digest.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_search_eval.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_search_p1.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_search_p2.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_search_p2b.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_search_p3.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_search_p4.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_search_p5.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_service_durability.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_session_benchmark.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_session_budget.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_shell_creds.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_shell_robustness.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_shell_telemetry_s0.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_shell_write_ledger.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_shell_writes.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_subproject_clear_scope.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_subproject_depth_consumers.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_subproject_exclusion.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_subproject_federation.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_subproject_linkage_api.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_subprojects.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_swe_bench.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_task_store.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_task_tool.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_time_tracker.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_token_telemetry.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_token_tracking.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_tool_registry.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_ui_jsx_syntax.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_upgrade_and_version.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_validate.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_vault_write_guard.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_version_sync.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_web_security.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tests/test_windows_reliability.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tui/__init__.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tui/backend.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tui/main.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tui/screens/__init__.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tui/screens/benchmark_view.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tui/screens/claudemd_view.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tui/screens/compress_view.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tui/screens/index_view.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tui/screens/init_view.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tui/screens/mcp_view.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tui/screens/optimize_view.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tui/screens/pipe_view.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tui/screens/projects_view.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tui/screens/search_view.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tui/screens/session_view.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tui/screens/stats.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.0}/tui/screens/ui_view.py +0 -0
- {code_context_control-2.111.0 → code_context_control-2.112.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.112.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,28 @@ 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). Auto-filters stdout >30 lines when it fits; auto-logs git mutations to
|
|
903
|
+
the edit ledger.
|
|
893
904
|
Credentials: env_creds='NAME1,NAME2' injects vault entries as env vars, and
|
|
894
905
|
{{cred:NAME}} inside cmd expands server-side — decoded values never enter
|
|
895
|
-
model context (see c3_credentials; echoed values are auto-redacted
|
|
906
|
+
model context (see c3_credentials; echoed values are auto-redacted, in the
|
|
907
|
+
response and in the kept output).
|
|
896
908
|
Best-effort block of catastrophic commands (rm -rf of /, a top-level system dir, or
|
|
897
909
|
$HOME/~; fork bombs; whole-drive wipes) — a guard, NOT a sandbox. Soft-warns on
|
|
898
910
|
--force, --no-verify, reset --hard.
|
|
@@ -904,7 +916,10 @@ async def c3_shell(cmd: str, cwd: str = "", timeout: int = 60,
|
|
|
904
916
|
return _finalize_response(ctx, name, args, resp, summ, **kw)
|
|
905
917
|
|
|
906
918
|
return await handle_shell(cmd, cwd, timeout, filter_output, log, svc, finalize,
|
|
907
|
-
env_creds=env_creds
|
|
919
|
+
env_creds=env_creds, output_id=output_id,
|
|
920
|
+
output_action=output_action, pattern=pattern,
|
|
921
|
+
lines=lines or None, stream=stream or "stdout",
|
|
922
|
+
max_bytes=max_bytes or None)
|
|
908
923
|
|
|
909
924
|
|
|
910
925
|
@mcp.tool()
|
|
@@ -29,8 +29,22 @@ from cli._shell_writes import shell_write_targets
|
|
|
29
29
|
from cli.tools import _grants
|
|
30
30
|
from cli.tools._helpers import finalize_with_tokens
|
|
31
31
|
from cli.tools.filter import handle_filter
|
|
32
|
+
from cli.tools.shell_render import (
|
|
33
|
+
allocate,
|
|
34
|
+
cmd_display,
|
|
35
|
+
effective_budget,
|
|
36
|
+
grep_pattern,
|
|
37
|
+
human_bytes,
|
|
38
|
+
shape_stream,
|
|
39
|
+
)
|
|
32
40
|
from core import count_tokens
|
|
33
41
|
from services import access_guard
|
|
42
|
+
from services.shell_output import (
|
|
43
|
+
TEXT_MAX_BYTES,
|
|
44
|
+
OutputAccessError,
|
|
45
|
+
ShellCapture,
|
|
46
|
+
ShellOutputStore,
|
|
47
|
+
)
|
|
34
48
|
|
|
35
49
|
# Commands that mutate repo state — trigger edit-ledger refresh after success.
|
|
36
50
|
_GIT_MUTATING = re.compile(
|
|
@@ -211,9 +225,28 @@ def _kill_tree(proc: subprocess.Popen) -> None:
|
|
|
211
225
|
pass
|
|
212
226
|
|
|
213
227
|
|
|
228
|
+
def _default_redact(text: str) -> str:
|
|
229
|
+
"""Scrub vault values from a piece of output; never raises."""
|
|
230
|
+
try:
|
|
231
|
+
from services import credential_store as _creds
|
|
232
|
+
return _creds.redact_text(text)
|
|
233
|
+
except Exception:
|
|
234
|
+
return text
|
|
235
|
+
|
|
236
|
+
|
|
214
237
|
def _run_sync(cmd: str, cwd: str, timeout: int,
|
|
215
|
-
extra_env: dict | None = None
|
|
216
|
-
|
|
238
|
+
extra_env: dict | None = None, *, redact=_default_redact,
|
|
239
|
+
spool_dir=None) -> dict:
|
|
240
|
+
"""Blocking subprocess run with hard kill on timeout. Returns structured dict.
|
|
241
|
+
|
|
242
|
+
Since 2.112.0 the child's streams are not buffered in memory: a
|
|
243
|
+
ShellCapture pumps them to spool files with bounded head/tail previews
|
|
244
|
+
(services/shell_output.py). ``stdout``/``stderr`` in the result carry the
|
|
245
|
+
whole text when the stream is at most TEXT_MAX_BYTES and None otherwise;
|
|
246
|
+
``capture`` carries the stats and previews either way. Callers that
|
|
247
|
+
patch this function with a plain dict (tests) still work: no ``capture``
|
|
248
|
+
means "small output, text present".
|
|
249
|
+
"""
|
|
217
250
|
start = time.time()
|
|
218
251
|
bash = _select_bash()
|
|
219
252
|
if bash:
|
|
@@ -229,7 +262,6 @@ def _run_sync(cmd: str, cwd: str, timeout: int,
|
|
|
229
262
|
proc = subprocess.Popen(
|
|
230
263
|
popen_target, shell=use_shell, cwd=cwd,
|
|
231
264
|
stdout=subprocess.PIPE, stderr=subprocess.PIPE,
|
|
232
|
-
text=True, encoding="utf-8", errors="replace",
|
|
233
265
|
**_popen_kwargs(extra_env),
|
|
234
266
|
)
|
|
235
267
|
except (OSError, ValueError) as exc:
|
|
@@ -241,24 +273,27 @@ def _run_sync(cmd: str, cwd: str, timeout: int,
|
|
|
241
273
|
"timed_out": False,
|
|
242
274
|
"shell": shell_name,
|
|
243
275
|
}
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
276
|
+
if spool_dir is None:
|
|
277
|
+
spool_dir = ShellOutputStore().spool_dir()
|
|
278
|
+
capture = ShellCapture(proc, spool_dir, redact=redact, kill_tree=_kill_tree)
|
|
279
|
+
timed_out = capture.wait(timeout)
|
|
280
|
+
|
|
281
|
+
def _text(stream: str):
|
|
282
|
+
if getattr(capture.stats, stream).bytes > TEXT_MAX_BYTES:
|
|
283
|
+
return None
|
|
249
284
|
try:
|
|
250
|
-
|
|
285
|
+
return capture.text(stream)
|
|
251
286
|
except Exception:
|
|
252
|
-
|
|
253
|
-
timed_out = True
|
|
287
|
+
return None
|
|
254
288
|
|
|
255
289
|
return {
|
|
256
290
|
"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),
|
|
291
|
+
"stdout": _text("stdout"),
|
|
292
|
+
"stderr": _text("stderr"),
|
|
293
|
+
"duration_ms": capture.duration_ms or round((time.time() - start) * 1000),
|
|
260
294
|
"timed_out": timed_out,
|
|
261
295
|
"shell": shell_name,
|
|
296
|
+
"capture": capture,
|
|
262
297
|
}
|
|
263
298
|
|
|
264
299
|
|
|
@@ -428,54 +463,121 @@ def _longest_line(*texts: str) -> int:
|
|
|
428
463
|
return longest
|
|
429
464
|
|
|
430
465
|
|
|
466
|
+
def _stream_facts(result: dict, stream: str) -> dict:
|
|
467
|
+
"""Size, line count, longest line and available text/previews of one stream."""
|
|
468
|
+
text = result.get(stream)
|
|
469
|
+
capture = result.get("capture")
|
|
470
|
+
if capture is not None:
|
|
471
|
+
st = getattr(capture.stats, stream)
|
|
472
|
+
return {"text": text, "head": st.head, "tail": st.tail, "bytes": st.bytes,
|
|
473
|
+
"lines": st.lines, "longest": st.longest_line}
|
|
474
|
+
text = text or ""
|
|
475
|
+
return {"text": text, "head": "", "tail": "", "bytes": len(text.encode("utf-8", errors="replace")),
|
|
476
|
+
"lines": text.count("\n") + (1 if text and not text.endswith("\n") else 0),
|
|
477
|
+
"longest": _longest_line(text)}
|
|
478
|
+
|
|
479
|
+
|
|
431
480
|
def render_shell_response(cmd: str, result: dict, svc, *,
|
|
432
481
|
filter_output: bool = True, warn: str = "",
|
|
433
482
|
capped_note: str = "", touched_files=(),
|
|
434
|
-
cred_names=(), swept_ghosts=()
|
|
483
|
+
cred_names=(), swept_ghosts=(),
|
|
484
|
+
max_bytes: int | None = None) -> tuple[str, dict]:
|
|
435
485
|
"""Turn a finished command into the body the agent reads, plus its stats.
|
|
436
486
|
|
|
437
487
|
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
|
-
|
|
488
|
+
returns (exit_code, stdout, stderr, duration_ms, timed_out, shell, and
|
|
489
|
+
since 2.112.0 an optional ``capture`` with stats and head/tail previews
|
|
490
|
+
for a stream too large to hold), so the shell-eval harness
|
|
491
|
+
(services/bench/shell_eval.py) can feed captured or synthetic streams
|
|
492
|
+
through exactly the code path a live call uses.
|
|
493
|
+
|
|
494
|
+
Budget (2.112.0, cli/tools/shell_render.py): the rendered body never
|
|
495
|
+
exceeds ``effective_budget()`` bytes — 18 KiB by default, 22 KiB ceiling,
|
|
496
|
+
``max_bytes`` and ``hybrid.shell_budget_bytes`` may only lower it,
|
|
497
|
+
``filter_output=False`` never lifts it. A stream that fits its share
|
|
498
|
+
passes through untouched (and, when it has more than
|
|
499
|
+
_FILTER_THRESHOLD_LINES newlines and is not a git diagnostic, through the
|
|
500
|
+
same auto-filter as before); a stream that does not is clipped line by
|
|
501
|
+
line and windowed head/tail with an omission note naming the output id.
|
|
502
|
+
Whenever anything was dropped — clipped, windowed or filtered — the raw
|
|
503
|
+
streams are kept in the spill store and ``stats["needs_spill"]`` tells
|
|
504
|
+
handle_shell to promote them.
|
|
444
505
|
|
|
445
506
|
``stats`` is what telemetry records about the call (see
|
|
446
507
|
SessionManager.record_tool_tokens ``detail``): stdout_bytes and
|
|
447
|
-
stderr_bytes are measured BEFORE filtering
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
508
|
+
stderr_bytes are measured BEFORE filtering; longest_line is the tell for
|
|
509
|
+
the single-line monsters (minified bundles, JSONL) that a newline-count
|
|
510
|
+
trigger never sees; filtered/spilled/output_id describe what this
|
|
511
|
+
renderer did.
|
|
451
512
|
"""
|
|
452
|
-
|
|
453
|
-
|
|
513
|
+
out = _stream_facts(result, "stdout")
|
|
514
|
+
err = _stream_facts(result, "stderr")
|
|
515
|
+
capture = result.get("capture")
|
|
454
516
|
stats: dict = {
|
|
455
517
|
"exit_code": result.get("exit_code"),
|
|
456
518
|
"timed_out": bool(result.get("timed_out")),
|
|
457
|
-
"stdout_bytes":
|
|
458
|
-
"stderr_bytes":
|
|
459
|
-
"longest_line":
|
|
519
|
+
"stdout_bytes": out["bytes"],
|
|
520
|
+
"stderr_bytes": err["bytes"],
|
|
521
|
+
"longest_line": max(out["longest"], err["longest"]),
|
|
460
522
|
"filtered": False,
|
|
461
523
|
"spilled": False,
|
|
462
524
|
"output_id": None,
|
|
463
525
|
"cmd_class": _cmd_class(cmd),
|
|
526
|
+
"needs_spill": False,
|
|
464
527
|
}
|
|
465
528
|
|
|
466
|
-
|
|
529
|
+
config_default = None
|
|
530
|
+
try:
|
|
531
|
+
config_default = (getattr(svc, "hybrid_config", None) or {}).get("shell_budget_bytes")
|
|
532
|
+
except Exception:
|
|
533
|
+
config_default = None
|
|
534
|
+
budget = effective_budget(max_bytes, config_default=config_default)
|
|
535
|
+
out_alloc, err_alloc = allocate(budget, out["bytes"], err["bytes"])
|
|
536
|
+
stats["budget_bytes"] = budget
|
|
537
|
+
output_id = getattr(capture, "output_id", None) if capture is not None else None
|
|
538
|
+
focus = grep_pattern(cmd)
|
|
539
|
+
|
|
540
|
+
# Legacy auto-filter: only on stdout, only when the whole text is at hand
|
|
541
|
+
# (a stream over TEXT_MAX_BYTES has previews only and goes straight to
|
|
542
|
+
# deterministic shaping), more than _FILTER_THRESHOLD_LINES newlines,
|
|
543
|
+
# never a git diagnostic — exactly the trigger 2.111.0 had, so the token
|
|
544
|
+
# profile of a filtered test or build run does not move in S1; what
|
|
545
|
+
# moves is that the dropped text is now recoverable. S2 replaces this.
|
|
546
|
+
stdout_text = out["text"]
|
|
467
547
|
filtered_note = ""
|
|
468
|
-
if (filter_output and
|
|
548
|
+
if (filter_output and stdout_text is not None
|
|
549
|
+
and stdout_text.count("\n") > _FILTER_THRESHOLD_LINES
|
|
469
550
|
and not _GIT_DIAGNOSTIC.search(cmd)):
|
|
470
551
|
try:
|
|
471
|
-
|
|
472
|
-
"",
|
|
552
|
+
stdout_text = handle_filter(
|
|
553
|
+
"", stdout_text, "", 50, "smart", True,
|
|
473
554
|
svc, lambda *a, **kw: a[2],
|
|
474
555
|
)
|
|
475
556
|
filtered_note = " [stdout filtered]"
|
|
476
557
|
stats["filtered"] = True
|
|
477
558
|
except Exception:
|
|
478
|
-
|
|
559
|
+
stdout_text = out["text"]
|
|
560
|
+
|
|
561
|
+
shaped_out, info_out = shape_stream(
|
|
562
|
+
full_text=stdout_text, head=out["head"], tail=out["tail"],
|
|
563
|
+
total_bytes=out["bytes"], total_lines=out["lines"], alloc=out_alloc,
|
|
564
|
+
output_id=output_id, focus=focus,
|
|
565
|
+
number_lines=not stats["filtered"]) # filtered text no longer maps to raw line numbers
|
|
566
|
+
if err["bytes"] > 0 or (err["text"] or "").strip():
|
|
567
|
+
shaped_err, info_err = shape_stream(
|
|
568
|
+
full_text=err["text"], head=err["head"], tail=err["tail"],
|
|
569
|
+
total_bytes=err["bytes"], total_lines=err["lines"], alloc=err_alloc,
|
|
570
|
+
output_id=output_id, focus=focus)
|
|
571
|
+
else:
|
|
572
|
+
shaped_err, info_err = "", {"cut": False, "omitted_lines": 0, "omitted_bytes": 0,
|
|
573
|
+
"clipped_lines": 0, "rendered_bytes": 0}
|
|
574
|
+
|
|
575
|
+
cut = bool(info_out["cut"] or info_err["cut"])
|
|
576
|
+
stats["needs_spill"] = bool(stats["filtered"] or cut)
|
|
577
|
+
stats["spilled"] = bool(stats["needs_spill"] and output_id)
|
|
578
|
+
stats["output_id"] = output_id if stats["spilled"] else None
|
|
579
|
+
stats["omitted_lines"] = info_out["omitted_lines"] + info_err["omitted_lines"]
|
|
580
|
+
stats["clipped_lines"] = info_out["clipped_lines"] + info_err["clipped_lines"]
|
|
479
581
|
|
|
480
582
|
if result.get("timed_out"):
|
|
481
583
|
status = "TIMEOUT"
|
|
@@ -484,14 +586,20 @@ def render_shell_response(cmd: str, result: dict, svc, *,
|
|
|
484
586
|
else:
|
|
485
587
|
status = f"FAIL({result.get('exit_code')})"
|
|
486
588
|
|
|
589
|
+
size_note = ""
|
|
590
|
+
if cut or stats["spilled"]:
|
|
591
|
+
size_note = (f" (stdout {human_bytes(out['bytes'])}/{out['lines']} lines,"
|
|
592
|
+
f" stderr {human_bytes(err['bytes'])}/{err['lines']} lines,")
|
|
593
|
+
size_note += f" output_id={output_id})" if stats["spilled"] else " not spilled)"
|
|
594
|
+
|
|
487
595
|
body = (
|
|
488
596
|
f"{warn}{capped_note}"
|
|
489
|
-
f"[c3_shell:{status}] {result.get('duration_ms', 0)}ms{filtered_note}\n"
|
|
490
|
-
f"$ {cmd}\n"
|
|
491
|
-
f"--- stdout ---\n{
|
|
597
|
+
f"[c3_shell:{status}] {result.get('duration_ms', 0)}ms{filtered_note}{size_note}\n"
|
|
598
|
+
f"$ {cmd_display(cmd)}\n"
|
|
599
|
+
f"--- stdout ---\n{shaped_out.rstrip()}\n"
|
|
492
600
|
)
|
|
493
|
-
if
|
|
494
|
-
body += f"--- stderr ---\n{
|
|
601
|
+
if shaped_err.strip():
|
|
602
|
+
body += f"--- stderr ---\n{shaped_err.rstrip()}\n"
|
|
495
603
|
dependency_hint = _dependency_hint(cmd, result)
|
|
496
604
|
if dependency_hint:
|
|
497
605
|
body += f"--- hint ---\n{dependency_hint}\n"
|
|
@@ -724,9 +832,102 @@ def _shell_warn_grant(svc, work_cwd: str) -> str | None:
|
|
|
724
832
|
return None
|
|
725
833
|
|
|
726
834
|
|
|
835
|
+
_OUTPUT_ACTIONS = ("read", "search", "tail", "delete")
|
|
836
|
+
|
|
837
|
+
|
|
838
|
+
def _handle_output(output_id: str, action: str, pattern: str, lines, stream: str,
|
|
839
|
+
max_bytes, svc, finalize) -> str:
|
|
840
|
+
"""Page a spilled output back by id (2.112.0).
|
|
841
|
+
|
|
842
|
+
The id is resolved for THIS project and THIS host session under the
|
|
843
|
+
CURRENT Access Guard rules — services/shell_output.py documents why a
|
|
844
|
+
spill from a more privileged call must not be readable by a later, less
|
|
845
|
+
privileged one. Every read is re-budgeted like a live response.
|
|
846
|
+
"""
|
|
847
|
+
action = (action or "read").strip().lower()
|
|
848
|
+
if action not in _OUTPUT_ACTIONS:
|
|
849
|
+
return (f"[c3_shell:error] output_action must be one of {', '.join(_OUTPUT_ACTIONS)}; "
|
|
850
|
+
f"got {action!r}")
|
|
851
|
+
stream = (stream or "stdout").strip().lower()
|
|
852
|
+
if stream not in ("stdout", "stderr"):
|
|
853
|
+
return "[c3_shell:error] stream must be 'stdout' or 'stderr'"
|
|
854
|
+
project_path = str(svc.project_path)
|
|
855
|
+
|
|
856
|
+
def guard_check(path: str):
|
|
857
|
+
try:
|
|
858
|
+
return access_guard.check(path, "read", project_path)
|
|
859
|
+
except Exception as exc: # evaluator error fails closed
|
|
860
|
+
return access_guard.Denial("<evaluator-error>", "deny", "builtin",
|
|
861
|
+
f"evaluator error: {type(exc).__name__}")
|
|
862
|
+
|
|
863
|
+
store = ShellOutputStore()
|
|
864
|
+
try:
|
|
865
|
+
meta = store.resolve(output_id, project_path=project_path,
|
|
866
|
+
session_id=_grants.session_id(svc), guard_check=guard_check)
|
|
867
|
+
except OutputAccessError as exc:
|
|
868
|
+
return f"[c3_shell:error] {exc}"
|
|
869
|
+
config_default = None
|
|
870
|
+
try:
|
|
871
|
+
config_default = (getattr(svc, "hybrid_config", None) or {}).get("shell_budget_bytes")
|
|
872
|
+
except Exception:
|
|
873
|
+
pass
|
|
874
|
+
budget = effective_budget(max_bytes, config_default=config_default) - 512
|
|
875
|
+
facts = getattr(meta, stream) or {}
|
|
876
|
+
header = (f"[c3_shell:output] {meta.id} {action} {stream} · $ {meta.cmd_display} · "
|
|
877
|
+
f"exit {meta.exit_code}{' (timed out)' if meta.timed_out else ''} · "
|
|
878
|
+
f"{human_bytes(facts.get('bytes', 0))}/{facts.get('lines', 0)} lines · "
|
|
879
|
+
f"captured {meta.created_at[:19]}\n")
|
|
880
|
+
try:
|
|
881
|
+
if action == "delete":
|
|
882
|
+
store.delete(meta)
|
|
883
|
+
body = header + "deleted\n"
|
|
884
|
+
elif action == "search":
|
|
885
|
+
if not pattern:
|
|
886
|
+
return "[c3_shell:error] output_action='search' needs a pattern"
|
|
887
|
+
body = header + store.search(meta, pattern, stream, max_bytes=budget)
|
|
888
|
+
elif action == "tail":
|
|
889
|
+
n = 50
|
|
890
|
+
if isinstance(lines, int) and lines > 0:
|
|
891
|
+
n = lines
|
|
892
|
+
body = header + store.tail(meta, stream, lines=n, max_bytes=budget)
|
|
893
|
+
else:
|
|
894
|
+
window = None
|
|
895
|
+
if isinstance(lines, (list, tuple)) and len(lines) == 2:
|
|
896
|
+
window = (int(lines[0]), int(lines[1]))
|
|
897
|
+
elif isinstance(lines, int) and lines > 0:
|
|
898
|
+
window = (lines, lines)
|
|
899
|
+
elif isinstance(lines, str) and lines.strip():
|
|
900
|
+
parts = [p for p in re.split(r"[,\-:\s]+", lines.strip()) if p]
|
|
901
|
+
if len(parts) == 1:
|
|
902
|
+
window = (int(parts[0]), int(parts[0]))
|
|
903
|
+
elif len(parts) >= 2:
|
|
904
|
+
window = (int(parts[0]), int(parts[1]))
|
|
905
|
+
body = header + store.read(meta, stream, lines=window, max_bytes=budget)
|
|
906
|
+
except (ValueError, re.error) as exc:
|
|
907
|
+
return f"[c3_shell:error] {exc}"
|
|
908
|
+
if not body.endswith("\n"):
|
|
909
|
+
body += "\n"
|
|
910
|
+
return finalize_with_tokens(
|
|
911
|
+
finalize, svc, "c3_shell",
|
|
912
|
+
{"output_id": output_id, "output_action": action},
|
|
913
|
+
body, f"shell output {action} {output_id}",
|
|
914
|
+
detail={"cmd_class": "output", "output_id": output_id, "output_action": action,
|
|
915
|
+
"response_bytes": len(body.encode("utf-8", errors="replace")),
|
|
916
|
+
"response_tokens": count_tokens(body)},
|
|
917
|
+
response_tokens=count_tokens(body),
|
|
918
|
+
)
|
|
919
|
+
|
|
920
|
+
|
|
727
921
|
async def handle_shell(cmd: str, cwd: str, timeout: int, filter_output: bool,
|
|
728
922
|
log: bool, svc, finalize, env_creds: str = "",
|
|
729
|
-
enable_creds: bool = True
|
|
923
|
+
enable_creds: bool = True, *, output_id: str = "",
|
|
924
|
+
output_action: str = "", pattern: str = "",
|
|
925
|
+
lines=None, stream: str = "stdout",
|
|
926
|
+
max_bytes: int | None = None) -> str:
|
|
927
|
+
if output_id:
|
|
928
|
+
return await asyncio.to_thread(
|
|
929
|
+
_handle_output, output_id, output_action, pattern, lines, stream,
|
|
930
|
+
max_bytes, svc, finalize)
|
|
730
931
|
if not cmd or not cmd.strip():
|
|
731
932
|
return "[c3_shell:error] empty command"
|
|
732
933
|
# _BLOCKED never consults grants — no approval flow reaches the
|
|
@@ -860,16 +1061,23 @@ async def handle_shell(cmd: str, cwd: str, timeout: int, filter_output: bool,
|
|
|
860
1061
|
else None
|
|
861
1062
|
)
|
|
862
1063
|
|
|
1064
|
+
# Decoded values a child process may echo (env dumps, set, crash output)
|
|
1065
|
+
# are scrubbed IN THE STREAM by _run_sync's redactor, before a byte
|
|
1066
|
+
# reaches the spool or any preview, so neither the response nor a spill
|
|
1067
|
+
# ever holds one.
|
|
863
1068
|
result = await asyncio.to_thread(
|
|
864
1069
|
_run_sync, exec_cmd, work_cwd, timeout, extra_env or None)
|
|
1070
|
+
capture = result.get("capture")
|
|
865
1071
|
|
|
866
1072
|
swept_ghosts = _sweep_new_ghost_files(ghost_root, _ghosts_before)
|
|
867
1073
|
|
|
868
|
-
#
|
|
869
|
-
#
|
|
1074
|
+
# Belt over the in-stream scrub for the small-output text (and for a
|
|
1075
|
+
# result a test handed in without a capture).
|
|
870
1076
|
if enable_creds:
|
|
871
|
-
result
|
|
872
|
-
|
|
1077
|
+
if result.get("stdout") is not None:
|
|
1078
|
+
result["stdout"] = _creds.redact_text(result["stdout"])
|
|
1079
|
+
if result.get("stderr") is not None:
|
|
1080
|
+
result["stderr"] = _creds.redact_text(result["stderr"])
|
|
873
1081
|
if cred_names:
|
|
874
1082
|
# Usage state is keyed by entry NAME; collapse dotted field refs.
|
|
875
1083
|
_creds.touch_last_used(
|
|
@@ -936,12 +1144,45 @@ async def handle_shell(cmd: str, cwd: str, timeout: int, filter_output: bool,
|
|
|
936
1144
|
f"run_in_background, which is not bound by this limit.\n"
|
|
937
1145
|
)
|
|
938
1146
|
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
1147
|
+
try:
|
|
1148
|
+
body, stats = await asyncio.to_thread(
|
|
1149
|
+
render_shell_response, cmd, result, svc,
|
|
1150
|
+
filter_output=filter_output, warn=warn, capped_note=capped_note,
|
|
1151
|
+
touched_files=touched_files, cred_names=cred_names,
|
|
1152
|
+
swept_ghosts=swept_ghosts, max_bytes=max_bytes,
|
|
1153
|
+
)
|
|
1154
|
+
# Keep the raw streams only when the body dropped something: the
|
|
1155
|
+
# spill is what makes a clipped or filtered response recoverable
|
|
1156
|
+
# without re-running the command (docs/shell-output.md).
|
|
1157
|
+
if capture is not None:
|
|
1158
|
+
if stats.get("needs_spill"):
|
|
1159
|
+
try:
|
|
1160
|
+
ShellOutputStore().promote(
|
|
1161
|
+
capture, project_path=str(svc.project_path),
|
|
1162
|
+
session_id=_grants.session_id(svc), cmd=cmd, cwd=work_cwd,
|
|
1163
|
+
guard_paths=_scan_candidates(cmd, work_cwd),
|
|
1164
|
+
exit_code=result.get("exit_code", -1),
|
|
1165
|
+
timed_out=bool(result.get("timed_out")),
|
|
1166
|
+
duration_ms=result.get("duration_ms", 0))
|
|
1167
|
+
except Exception as exc:
|
|
1168
|
+
stats["spilled"] = False
|
|
1169
|
+
stats["output_id"] = None
|
|
1170
|
+
body += (f"[c3_shell:note] the raw output could not be kept "
|
|
1171
|
+
f"({type(exc).__name__}: {exc}); the output id above is not retrievable\n")
|
|
1172
|
+
try:
|
|
1173
|
+
capture.discard()
|
|
1174
|
+
except Exception:
|
|
1175
|
+
pass
|
|
1176
|
+
else:
|
|
1177
|
+
capture.discard()
|
|
1178
|
+
except Exception:
|
|
1179
|
+
if capture is not None:
|
|
1180
|
+
try:
|
|
1181
|
+
capture.discard()
|
|
1182
|
+
except Exception:
|
|
1183
|
+
pass
|
|
1184
|
+
raise
|
|
1185
|
+
stats.pop("needs_spill", None)
|
|
945
1186
|
|
|
946
1187
|
if result["timed_out"]:
|
|
947
1188
|
status = "TIMEOUT"
|