code-context-control 2.146.0__tar.gz → 2.152.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.146.0 → code_context_control-2.152.0}/PKG-INFO +1 -1
- {code_context_control-2.146.0 → code_context_control-2.152.0}/cli/c3.py +1 -1
- {code_context_control-2.146.0 → code_context_control-2.152.0}/cli/guide/tools.html +1 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/cli/hook_access_guard.py +1 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/cli/hub_server.py +231 -20
- {code_context_control-2.146.0 → code_context_control-2.152.0}/cli/hub_ui/components/hub_access.js +119 -2
- {code_context_control-2.146.0 → code_context_control-2.152.0}/cli/hub_ui/components/modals.js +34 -12
- {code_context_control-2.146.0 → code_context_control-2.152.0}/cli/hub_ui/components/settings_modal.js +11 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/cli/mcp_server.py +18 -5
- code_context_control-2.152.0/cli/tools/_edit_report.py +186 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/cli/tools/edit.py +196 -118
- {code_context_control-2.146.0 → code_context_control-2.152.0}/cli/tools/edit_verify.py +7 -4
- {code_context_control-2.146.0 → code_context_control-2.152.0}/cli/tools/edits.py +112 -2
- {code_context_control-2.146.0 → code_context_control-2.152.0}/cli/tools/read.py +2 -1
- {code_context_control-2.146.0 → code_context_control-2.152.0}/code_context_control.egg-info/PKG-INFO +1 -1
- {code_context_control-2.146.0 → code_context_control-2.152.0}/code_context_control.egg-info/SOURCES.txt +11 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/pyproject.toml +1 -1
- {code_context_control-2.146.0 → code_context_control-2.152.0}/services/access_guard.py +61 -5
- {code_context_control-2.146.0 → code_context_control-2.152.0}/services/atomic_json.py +25 -8
- code_context_control-2.152.0/services/builtin_leases.py +182 -0
- code_context_control-2.152.0/services/edit_blobs.py +192 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/services/project_manager.py +10 -2
- code_context_control-2.152.0/services/read_stamps.py +287 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_access_guard_meta.py +1 -0
- code_context_control-2.152.0/tests/test_builtin_leases.py +210 -0
- code_context_control-2.152.0/tests/test_edit_eol_atomic.py +223 -0
- code_context_control-2.152.0/tests/test_edit_report.py +142 -0
- code_context_control-2.152.0/tests/test_edit_revert.py +204 -0
- code_context_control-2.152.0/tests/test_edit_stale.py +214 -0
- code_context_control-2.152.0/tests/test_hub_builtin_routes.py +163 -0
- code_context_control-2.152.0/tests/test_hub_ide_cmd.py +125 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/LICENSE +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/README.md +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/cli/__init__.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/cli/_hook_utils.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/cli/_shell_writes.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/cli/commands/__init__.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/cli/commands/common.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/cli/commands/parser.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/cli/docs.html +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/cli/edits.html +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/cli/guide/access.html +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/cli/guide/bitbucket.html +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/cli/guide/ci.html +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/cli/guide/credentials.html +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/cli/guide/delegate.html +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/cli/guide/getting-started.html +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/cli/guide/index.html +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/cli/guide/jira.html +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/cli/guide/masking.html +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/cli/guide/oracle.html +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/cli/guide/sessions.html +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/cli/guide/shared.css +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/cli/guide/workflow.html +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/cli/hook_agent_model.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/cli/hook_artifact.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/cli/hook_auto_snapshot.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/cli/hook_c3_signal.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/cli/hook_c3read.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/cli/hook_codex_lifecycle.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/cli/hook_dispatch.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/cli/hook_edit_ledger.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/cli/hook_edit_unlock.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/cli/hook_filter.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/cli/hook_ghost_files.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/cli/hook_pretool_enforce.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/cli/hook_prompt_recall.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/cli/hook_read.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/cli/hook_session_end.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/cli/hook_session_open.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/cli/hook_session_stats.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/cli/hook_terse_advisor.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/cli/hub_ui/app.js +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/cli/hub_ui/components/add_project.js +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/cli/hub_ui/components/config_editor.js +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/cli/hub_ui/components/drill_artifacts.js +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/cli/hub_ui/components/drill_health.js +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/cli/hub_ui/components/drill_panel.js +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/cli/hub_ui/components/drill_subprojects.js +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/cli/hub_ui/components/drill_tasks.js +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/cli/hub_ui/components/drill_views.js +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/cli/hub_ui/components/global_search.js +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/cli/hub_ui/components/hub_ci.js +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/cli/hub_ui/components/hub_cred_audit.js +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/cli/hub_ui/components/hub_credentials.js +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/cli/hub_ui/components/hub_enforcement.js +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/cli/hub_ui/components/hub_locks.js +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/cli/hub_ui/components/hub_sessions.js +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/cli/hub_ui/components/hub_tokens.js +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/cli/hub_ui/components/mcp_manager.js +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/cli/hub_ui/components/project_card.js +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/cli/hub_ui/components/project_tree.js +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/cli/hub_ui/components/session_drawer.js +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/cli/hub_ui/components/sidebar.js +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/cli/hub_ui/components/summary_bar.js +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/cli/hub_ui/components/task_board.js +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/cli/hub_ui/components/toasts.js +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/cli/hub_ui/components/topbar.js +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/cli/hub_ui/state.js +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/cli/hub_ui.html +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/cli/mcp_proxy.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/cli/progress.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/cli/server.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/cli/tools/__init__.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/cli/tools/_grants.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/cli/tools/_helpers.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/cli/tools/agent.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/cli/tools/artifacts.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/cli/tools/bitbucket.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/cli/tools/ci.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/cli/tools/compress.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/cli/tools/credentials.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/cli/tools/delegate.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/cli/tools/federate.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/cli/tools/filter.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/cli/tools/impact.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/cli/tools/jira.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/cli/tools/locks.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/cli/tools/memory.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/cli/tools/override.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/cli/tools/project.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/cli/tools/search.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/cli/tools/session.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/cli/tools/shell.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/cli/tools/shell_job.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/cli/tools/shell_nudge.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/cli/tools/shell_parsers.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/cli/tools/shell_render.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/cli/tools/status.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/cli/tools/tasks.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/cli/tools/validate.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/cli/ui/api.js +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/cli/ui/app.js +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/cli/ui/components/access.js +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/cli/ui/components/bitbucket.js +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/cli/ui/components/chat.js +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/cli/ui/components/credentials.js +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/cli/ui/components/dashboard.js +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/cli/ui/components/edits.js +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/cli/ui/components/enforcement.js +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/cli/ui/components/instructions.js +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/cli/ui/components/jira.js +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/cli/ui/components/memory.js +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/cli/ui/components/sessions.js +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/cli/ui/components/settings.js +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/cli/ui/components/sidebar.js +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/cli/ui/components/tasks.js +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/cli/ui/icons.js +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/cli/ui/pm_shared.js +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/cli/ui/shared.js +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/cli/ui/theme.js +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/cli/ui.html +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/cli/ui_legacy.html +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/cli/ui_nano.html +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/code_context_control.egg-info/dependency_links.txt +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/code_context_control.egg-info/entry_points.txt +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/code_context_control.egg-info/requires.txt +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/code_context_control.egg-info/top_level.txt +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/core/__init__.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/core/codex_patch.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/core/config.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/core/grok_payload.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/core/hook_command.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/core/host.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/core/ide.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/core/mcp_toml.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/core/web_security.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/oracle/__init__.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/oracle/config.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/oracle/listeners.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/oracle/mcp_oracle.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/oracle/oracle_server.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/oracle/oracle_ui.html +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/oracle/services/__init__.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/oracle/services/activity_reporter.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/oracle/services/api_auth.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/oracle/services/c3_bridge.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/oracle/services/chat_engine.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/oracle/services/chat_poll.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/oracle/services/chat_store.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/oracle/services/client_tokens.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/oracle/services/cross_memory.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/oracle/services/discovery_audit.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/oracle/services/federated_graph.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/oracle/services/health_checker.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/oracle/services/insight_engine.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/oracle/services/local_session.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/oracle/services/memory_reader.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/oracle/services/memory_writer.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/oracle/services/mobile_api.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/oracle/services/project_scanner.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/oracle/services/review_agent.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/oracle/services/tool_executor.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/oracle/services/tool_registry.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/oracle/ui/activity.js +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/oracle/ui/agents.js +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/oracle/ui/app.js +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/oracle/ui/busy.js +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/oracle/ui/chat/conversations.js +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/oracle/ui/chat/input.js +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/oracle/ui/chat/markdown.js +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/oracle/ui/chat/send.js +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/oracle/ui/chat/stream_renderer.js +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/oracle/ui/chat/toolbar.js +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/oracle/ui/core.js +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/oracle/ui/crossgraph.js +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/oracle/ui/header.js +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/oracle/ui/insights.js +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/oracle/ui/projects.js +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/oracle/ui/qrcode.js +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/oracle/ui/settings.js +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/oracle/ui/suggestions.js +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/oracle/ui/theme_tabs.js +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/services/__init__.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/services/access_telemetry.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/services/activity_log.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/services/agent_base.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/services/agent_downshift.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/services/agent_locks.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/services/agents.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/services/agents_workflow.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/services/artifact_defs.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/services/artifact_store.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/services/auto_memory.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/services/background_service.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/services/bench/__init__.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/services/bench/delegate_eval.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/services/bench/delegate_write_eval.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/services/bench/external/__init__.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/services/bench/external/aider_polyglot.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/services/bench/external/swe_bench.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/services/bench/map_eval.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/services/bench/search_eval.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/services/bench/shell_eval.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/services/benchmark_dashboard.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/services/bitbucket_client.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/services/bitbucket_credentials.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/services/ci_act.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/services/ci_cache.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/services/ci_expr.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/services/ci_failures.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/services/ci_github.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/services/ci_impact.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/services/ci_intel.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/services/ci_runner.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/services/ci_workflow.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/services/circuit_breaker.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/services/claude_md.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/services/codex_integration.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/services/codex_transcript.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/services/compressor.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/services/context_snapshot.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/services/conversation_store.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/services/cred_audit.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/services/cred_telemetry.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/services/credential_backup.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/services/credential_store.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/services/delegate_agents.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/services/delegate_hints.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/services/delegate_write.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/services/dir_map.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/services/doc_index.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/services/e2e_benchmark.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/services/e2e_evaluator.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/services/e2e_tasks.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/services/edit_ledger.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/services/embedding_index.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/services/enforcement_policy.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/services/error_reporting.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/services/file_map.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/services/file_memory.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/services/git_context.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/services/grok_integration.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/services/grok_transcript.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/services/host_sessions.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/services/hub_service.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/services/index_store.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/services/indexer.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/services/jira_client.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/services/jira_cloud.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/services/jira_credentials.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/services/jira_data_center.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/services/jira_links.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/services/lexical_index.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/services/mask_activation.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/services/mask_mirror.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/services/mask_presets.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/services/memory.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/services/memory_consolidator.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/services/memory_distiller.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/services/memory_graph.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/services/memory_grounder.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/services/memory_queue.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/services/memory_scorer.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/services/metrics.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/services/notifications.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/services/ollama_bridge.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/services/ollama_client.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/services/ollama_credentials.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/services/oracle_service.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/services/output_filter.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/services/override_costs.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/services/override_grants.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/services/override_policy.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/services/override_requests.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/services/override_wake.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/services/parser.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/services/project_runtime.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/services/protocol.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/services/proxy_state.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/services/repo_map.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/services/repo_shape.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/services/reranker.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/services/retention.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/services/retrieval.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/services/retrieval_broker.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/services/router.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/services/runtime.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/services/scanner.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/services/session_benchmark.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/services/session_catalog.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/services/session_live.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/services/session_manager.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/services/session_preloader.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/services/shell_jobs.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/services/shell_output.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/services/subprojects.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/services/task_store.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/services/telemetry.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/services/terminal_launch.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/services/text_index.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/services/time_tracker.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/services/tool_classifier.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/services/transcript_index.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/services/validation_cache.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/services/vector_store.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/services/watcher.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/services/win_subprocess.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/setup.cfg +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_access_builtin_optout.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_access_guard.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_access_guard_shell_project.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_access_guard_surfaces.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_access_guard_wiring.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_activity_log_find_last.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_activity_reporter.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_agent_locks.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_aider_polyglot.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_antigravity_transition.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_artifact_store.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_artifact_tool.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_atomic_json.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_background_service.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_bitbucket_cli_smoke.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_bitbucket_client.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_bitbucket_config_fallback.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_bitbucket_credentials.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_bitbucket_tool.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_builtin_modes.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_c3_bridge_project_artifacts.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_c3_shell.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_chat_poll.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_ci_act.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_ci_cache.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_ci_dag_ownership.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_ci_expr.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_ci_impact.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_ci_intel.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_ci_runner.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_ci_workflow.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_circuit_breaker.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_claude_md_merge.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_claude_md_updater.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_cli_smoke.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_codex_mcp_transport.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_codex_native.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_compressor_large_file.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_confirm_guard.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_confirm_guard_wiring.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_cooccurrence_bounds.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_cred_audit.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_cred_telemetry.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_credential_backup.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_credential_login_kind.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_credential_store.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_credential_ui_parity.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_credentials_routes.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_credentials_tool.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_creds_cli_smoke.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_delegate_adoption_d4.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_delegate_auto.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_delegate_cascade.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_delegate_claude_d1.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_delegate_eval.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_delegate_grok.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_delegate_host_d2.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_delegate_scout_d3.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_delegate_telemetry_d0.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_delegate_thinking_cap.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_delegate_tuning.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_delegate_version_probe.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_delegate_write.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_delegate_write_eval.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_dir_map_c3.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_e2e_benchmark.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_edit_ledger_deadline.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_edit_ledger_hook.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_edit_locking.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_edit_normalization.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_edit_verify.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_embedding_index_corrupt_store.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_embedding_index_deadlock.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_enforcement_flip.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_enforcement_policy.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_enforcement_routes.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_env_parser.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_failed_calls_do_not_unlock.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_federated_graph.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_file_map_c1.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_filter_backoff.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_ghost_files.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_ghost_generation.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_git_branch_awareness.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_grok_native.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_hook_access_guard.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_hook_codex_compat.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_hook_dispatch.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_hook_grok_compat.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_hook_pretool_enforce.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_hook_prompt_recall.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_hook_session_end.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_hook_smoke.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_hook_state.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_hook_utf8_stdio.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_hub_access_routes.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_hub_credentials_route.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_hub_credentials_routes_write.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_hub_enforcement_routes.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_hub_hook_migration.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_hub_inspect_api.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_hub_locks_routes.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_hub_oracle_service_routes.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_hub_override_policy_routes.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_hub_override_routes.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_hub_rules_routes.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_hub_server_smoke.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_hub_sessions_routes.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_hub_subproject_links.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_ide_workflow_adaptation.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_index_cap_not_hardcoded.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_init_clear_preserves_user_content.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_init_scan.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_install_mcp_entrypoint.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_jira_cli_smoke.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_jira_client.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_jira_config_fallback.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_jira_credentials.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_jira_links.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_jira_routes.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_jira_tool.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_large_files_c4.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_lazy_store_init.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_map_eval.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_map_telemetry_c0.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_mask_guard.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_mask_routes.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_mask_surfaces.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_mcp_host_guard.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_mcp_memory_timeout.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_mcp_server_smoke.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_mcp_toml.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_memory_distiller.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_memory_graph_api.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_memory_queue.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_memory_system.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_mobile_api.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_mobile_clients.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_mobile_extras.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_mobile_jobs_ci.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_mobile_override_costs.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_mobile_override_routes.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_mobile_security_api.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_no_stale_model_pins.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_notification_dedup.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_notification_discipline.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_notification_kinds.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_ollama_credentials.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_oracle_api_auth.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_oracle_apikey_api.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_oracle_c3_bridge.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_oracle_chat_engine.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_oracle_chat_store.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_oracle_discovery_api.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_oracle_discovery_audit.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_oracle_health_probe.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_oracle_local_auth.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_oracle_loopback.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_oracle_ollama_bridge.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_oracle_scanner_cache.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_oracle_security_fixes.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_oracle_session_bootstrap.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_oracle_subproject_awareness.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_oracle_ui_bundle.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_output_filter.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_override_costs.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_override_grants.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_override_grants_mcp.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_override_requests.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_override_wake.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_permissions.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_pm_api.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_project_manager.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_project_manager_merge.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_project_tool.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_read_coercion.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_read_edit_parity.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_read_outside_root.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_related_facts.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_repo_map.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_repo_shape.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_response_boilerplate.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_retention.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_review_digest.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_search_eval.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_search_p1.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_search_p2.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_search_p2b.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_search_p3.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_search_p4.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_search_p5.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_service_durability.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_session_benchmark.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_session_budget.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_session_catalog.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_session_live.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_session_tool.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_shell_budget_s1.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_shell_creds.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_shell_eval.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_shell_jobs_s3.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_shell_nudge_s4.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_shell_output.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_shell_parsers_s2.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_shell_robustness.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_shell_telemetry_s0.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_shell_write_ledger.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_shell_writes.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_subproject_clear_scope.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_subproject_depth_consumers.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_subproject_exclusion.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_subproject_federation.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_subproject_linkage_api.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_subprojects.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_swe_bench.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_task_store.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_task_tool.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_time_tracker.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_token_telemetry.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_token_tracking.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_tool_registry.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_ui_jsx_syntax.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_upgrade_and_version.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_validate.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_vault_write_guard.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_version_sync.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_watcher_pruning.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_web_security.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tests/test_windows_reliability.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tui/__init__.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tui/backend.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tui/main.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tui/screens/__init__.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tui/screens/benchmark_view.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tui/screens/claudemd_view.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tui/screens/compress_view.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tui/screens/index_view.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tui/screens/init_view.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tui/screens/mcp_view.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tui/screens/optimize_view.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tui/screens/pipe_view.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tui/screens/projects_view.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tui/screens/search_view.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tui/screens/session_view.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tui/screens/stats.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.0}/tui/screens/ui_view.py +0 -0
- {code_context_control-2.146.0 → code_context_control-2.152.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.152.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
|
|
@@ -91,7 +91,7 @@ console = Console() if HAS_RICH else None
|
|
|
91
91
|
# Config
|
|
92
92
|
CONFIG_DIR = ".c3"
|
|
93
93
|
CONFIG_FILE = ".c3/config.json"
|
|
94
|
-
__version__ = "2.
|
|
94
|
+
__version__ = "2.152.0"
|
|
95
95
|
|
|
96
96
|
# The PreToolUse matcher for native subagent calls (installer and hub migration).
|
|
97
97
|
AGENT_MATCHER = "Agent|Task"
|
|
@@ -1507,6 +1507,7 @@ c3_agent(workflow=<span class="str">'investigate'</span>, context=<span class="s
|
|
|
1507
1507
|
<tr><td class="param-name">stats</td><td class="param-desc">Aggregate stats: most-edited files, change frequency</td></tr>
|
|
1508
1508
|
<tr><td class="param-name">tag</td><td class="param-desc">Tag an edit entry with a label</td></tr>
|
|
1509
1509
|
<tr><td class="param-name">verify</td><td class="param-desc"><strong>v2.75.0</strong> — did an edit land? Pass the SAME <code>file</code>/<code>old_string</code>/<code>new_string</code> (or <code>edits</code>) a failed or timed-out <code>c3_edit</code> call took. Answers APPLIED (do not retry) / NOT_APPLIED (safe to retry) / INCONCLUSIVE (read the file)</td></tr>
|
|
1510
|
+
<tr><td class="param-name">revert</td><td class="param-desc">Put a file back to the bytes it had before <code>edit_id</code>, from the pre-image <code>c3_edit</code> stored in <code>.c3/edit_blobs/</code>. Refuses if the file changed since (lists the later edit ids to revert first) or if no pre-image was kept (native Edit/shell rows, files over 5 MB, read-denied or masked paths, evicted blobs). Logs its own <code>reverted</code> row, which can itself be reverted.</td></tr>
|
|
1510
1511
|
</tbody>
|
|
1511
1512
|
</table>
|
|
1512
1513
|
|
|
@@ -447,6 +447,7 @@ def run(payload: dict, project_path: Path | None = None,
|
|
|
447
447
|
tool_input = payload.get("tool_input", {}) or {}
|
|
448
448
|
base = str(project_path if project_path is not None else Path.cwd())
|
|
449
449
|
session_id = str(payload.get("session_id") or "")
|
|
450
|
+
ag.bind_session(session_id)
|
|
450
451
|
|
|
451
452
|
if tool in _WRITE_TOOLS or tool in _READ_TOOLS:
|
|
452
453
|
fp = _target(tool_input)
|
|
@@ -72,6 +72,10 @@ _HUB_CONFIG_DEFAULTS = {
|
|
|
72
72
|
"projects_view": "list",
|
|
73
73
|
"main_view": "projects",
|
|
74
74
|
"oracle_url": "",
|
|
75
|
+
# Per-IDE launch command overrides, e.g. {"claude-code": "yep"} when the
|
|
76
|
+
# agent is started through a wrapper script instead of the stock binary.
|
|
77
|
+
# A project's own `ide_cmd` (projects.json) wins over this.
|
|
78
|
+
"ide_cmds": {},
|
|
75
79
|
# Minutes of project silence, with no session heartbeat left, before a UI
|
|
76
80
|
# server that an IDE session launched is stopped. 0 = never reap.
|
|
77
81
|
"ui_reap_minutes": 30,
|
|
@@ -81,6 +85,48 @@ _HUB_CONFIG_DEFAULTS = {
|
|
|
81
85
|
_MAIN_VIEWS = {"projects", "board", "ci", "creds", "tokens", "locks", "access",
|
|
82
86
|
"enforce", "sessions"}
|
|
83
87
|
|
|
88
|
+
# Stock command per IDE id, and whether it takes the project path as an
|
|
89
|
+
# argument (GUI) instead of being run inside a terminal at that path.
|
|
90
|
+
_IDE_DEFAULT_CMDS = {
|
|
91
|
+
"claude-code": ("claude", False),
|
|
92
|
+
"claude-app": ("claude-app", True),
|
|
93
|
+
"codex": ("codex", False),
|
|
94
|
+
"grok": ("grok", False),
|
|
95
|
+
"gemini": ("gemini", False),
|
|
96
|
+
"antigravity": ("antigravity", False),
|
|
97
|
+
"vscode": ("code", True),
|
|
98
|
+
"cursor": ("cursor", True),
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def _resolve_ide_cmd(ide: str, path: str, custom_cmd: str = "") -> tuple:
|
|
103
|
+
"""Resolve the command to launch for `ide` in `path`.
|
|
104
|
+
|
|
105
|
+
Precedence: explicit custom_cmd (this launch) → the project's stored
|
|
106
|
+
`ide_cmd` → hub config `ide_cmds[ide]` → the stock command.
|
|
107
|
+
Returns (cmd, is_gui, error) — error is a message when nothing resolves.
|
|
108
|
+
"""
|
|
109
|
+
default_cmd, is_gui = _IDE_DEFAULT_CMDS.get(ide, ("", False))
|
|
110
|
+
if ide != "custom" and not default_cmd:
|
|
111
|
+
return "", False, f"Unknown IDE: {ide}"
|
|
112
|
+
cmd = (custom_cmd or "").strip()
|
|
113
|
+
if not cmd:
|
|
114
|
+
try:
|
|
115
|
+
cmd = _pm().get_ide_cmd(path)
|
|
116
|
+
except Exception:
|
|
117
|
+
cmd = ""
|
|
118
|
+
if not cmd:
|
|
119
|
+
overrides = _read_hub_config().get("ide_cmds") or {}
|
|
120
|
+
if isinstance(overrides, dict):
|
|
121
|
+
cmd = str(overrides.get(ide) or "").strip()
|
|
122
|
+
if not cmd:
|
|
123
|
+
cmd = default_cmd
|
|
124
|
+
if not cmd:
|
|
125
|
+
return "", False, "custom_cmd is required for custom IDE"
|
|
126
|
+
# An overridden command replaces the binary, not the launch style: a
|
|
127
|
+
# wrapper for a terminal CLI is still a terminal CLI.
|
|
128
|
+
return cmd, is_gui, ""
|
|
129
|
+
|
|
84
130
|
# How often the hub reaps orphaned UI servers and chases autostart projects.
|
|
85
131
|
_UI_SWEEP_INTERVAL_S = 60
|
|
86
132
|
|
|
@@ -460,6 +506,15 @@ def api_hub_config_set():
|
|
|
460
506
|
cfg["main_view"] = main_view
|
|
461
507
|
if "oracle_url" in data:
|
|
462
508
|
cfg["oracle_url"] = str(data["oracle_url"]).strip()
|
|
509
|
+
if "ide_cmds" in data:
|
|
510
|
+
raw = data["ide_cmds"]
|
|
511
|
+
if not isinstance(raw, dict):
|
|
512
|
+
return jsonify({"error": "ide_cmds must be an object"}), 400
|
|
513
|
+
# Empty string = "back to the stock command", so the key is dropped
|
|
514
|
+
# rather than stored blank.
|
|
515
|
+
cfg["ide_cmds"] = {
|
|
516
|
+
str(k): str(v).strip() for k, v in raw.items() if str(v or "").strip()
|
|
517
|
+
}
|
|
463
518
|
if "sidebar_group" in data:
|
|
464
519
|
cfg["sidebar_group"] = str(data["sidebar_group"]).strip()
|
|
465
520
|
if "sidebar_collapsed" in data:
|
|
@@ -718,17 +773,11 @@ def api_projects_open():
|
|
|
718
773
|
|
|
719
774
|
@app.route("/api/projects/launch-ide", methods=["POST"])
|
|
720
775
|
def api_launch_ide():
|
|
721
|
-
"""Launch an IDE or CLI tool in the project directory. Body: {path, ide, custom_cmd?}
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
"grok": ("grok", False),
|
|
727
|
-
"gemini": ("gemini", False),
|
|
728
|
-
"antigravity": ("antigravity", False),
|
|
729
|
-
"vscode": ("code", True),
|
|
730
|
-
"cursor": ("cursor", True),
|
|
731
|
-
}
|
|
776
|
+
"""Launch an IDE or CLI tool in the project directory. Body: {path, ide, custom_cmd?}
|
|
777
|
+
|
|
778
|
+
The command itself is resolved by _resolve_ide_cmd, so a project or the
|
|
779
|
+
hub can point `claude-code` at a wrapper such as `yep`.
|
|
780
|
+
"""
|
|
732
781
|
try:
|
|
733
782
|
data = request.get_json(force=True) or {}
|
|
734
783
|
path_str = (data.get("path") or "").strip()
|
|
@@ -744,14 +793,9 @@ def api_launch_ide():
|
|
|
744
793
|
if not path.exists():
|
|
745
794
|
return jsonify({"error": f"Path does not exist: {path_str}"}), 404
|
|
746
795
|
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
cmd, is_gui = custom_cmd, False
|
|
751
|
-
elif ide in _IDE_CMDS:
|
|
752
|
-
cmd, is_gui = _IDE_CMDS[ide]
|
|
753
|
-
else:
|
|
754
|
-
return jsonify({"error": f"Unknown IDE: {ide}"}), 400
|
|
796
|
+
cmd, is_gui, err = _resolve_ide_cmd(ide, str(path), custom_cmd)
|
|
797
|
+
if err:
|
|
798
|
+
return jsonify({"error": err}), 400
|
|
755
799
|
|
|
756
800
|
if is_gui:
|
|
757
801
|
# GUI IDEs (VS Code, Cursor) accept a path argument directly
|
|
@@ -795,7 +839,7 @@ def api_launch_ide():
|
|
|
795
839
|
|
|
796
840
|
@app.route("/api/projects/update", methods=["POST"])
|
|
797
841
|
def api_projects_update():
|
|
798
|
-
"""Update editable project fields
|
|
842
|
+
"""Update editable project fields. Body: {path, name?, tags?, notes?, ide_cmd?}"""
|
|
799
843
|
data = request.get_json(force=True) or {}
|
|
800
844
|
path = (data.get("path") or "").strip()
|
|
801
845
|
if not path:
|
|
@@ -812,6 +856,9 @@ def api_projects_update():
|
|
|
812
856
|
fields["tags"] = [t.strip() for t in str(raw).split(",") if t.strip()]
|
|
813
857
|
if "notes" in data:
|
|
814
858
|
fields["notes"] = str(data["notes"])
|
|
859
|
+
if "ide_cmd" in data:
|
|
860
|
+
# Blank clears the override and falls back to the stock command.
|
|
861
|
+
fields["ide_cmd"] = str(data["ide_cmd"] or "").strip()
|
|
815
862
|
try:
|
|
816
863
|
ok = _pm().update_project(path, **fields)
|
|
817
864
|
return jsonify({"updated": ok})
|
|
@@ -3839,6 +3886,170 @@ def api_hub_access_rule_remove():
|
|
|
3839
3886
|
return jsonify(result)
|
|
3840
3887
|
|
|
3841
3888
|
|
|
3889
|
+
# ── Builtin guard modes (v2.147.0) ─────────────────────────────────────────
|
|
3890
|
+
|
|
3891
|
+
def _hub_human():
|
|
3892
|
+
"""The Desk client behind ``Authorization: Bearer``, else ``None``.
|
|
3893
|
+
|
|
3894
|
+
Loopback and the CSRF guard stop a browser, not a process on this
|
|
3895
|
+
machine: an agent can POST here as easily as a person. A Desk client
|
|
3896
|
+
token is minted only with ``bootstrap.key``, which Access Guard denies
|
|
3897
|
+
to agents, and is stored as a hash, so presenting one is the proof a
|
|
3898
|
+
loosening builtin change needs. A phone token does not count: builtin
|
|
3899
|
+
guards are not loosened from a device that leaves the building.
|
|
3900
|
+
"""
|
|
3901
|
+
from oracle.services import client_tokens
|
|
3902
|
+
scheme, _, token = (request.headers.get("Authorization") or "").partition(" ")
|
|
3903
|
+
if scheme.lower() != "bearer" or not token.strip():
|
|
3904
|
+
return None
|
|
3905
|
+
who = client_tokens.principal_for(token.strip())
|
|
3906
|
+
return who if who and who.get("kind") == "desk" else None
|
|
3907
|
+
|
|
3908
|
+
|
|
3909
|
+
@app.route("/api/hub/access/builtin", methods=["GET"])
|
|
3910
|
+
def api_hub_access_builtin():
|
|
3911
|
+
"""Every Tier-1 builtin with its live global mode, and each project's own.
|
|
3912
|
+
|
|
3913
|
+
Modes are read through the keyring (config and attestation must agree),
|
|
3914
|
+
so a mode listed here is one evaluation honours. ``projects`` holds only
|
|
3915
|
+
projects that set a mode of their own, or could not be read.
|
|
3916
|
+
``strictness`` ranks each mode 0 (allow) to 3 (full deny), so a client
|
|
3917
|
+
can tell loosening from tightening without knowing the tiers.
|
|
3918
|
+
"""
|
|
3919
|
+
try:
|
|
3920
|
+
global_modes = access_guard._scope_modes("global")
|
|
3921
|
+
except Exception as e:
|
|
3922
|
+
return jsonify({"error": str(e)}), 500
|
|
3923
|
+
home = access_guard._global_base()
|
|
3924
|
+
guards = []
|
|
3925
|
+
for glob in access_guard.DISABLEABLE_BUILTINS:
|
|
3926
|
+
canon = access_guard._norm_builtin(glob)
|
|
3927
|
+
guards.append({
|
|
3928
|
+
"glob": canon,
|
|
3929
|
+
"global": global_modes.get(canon, "default"),
|
|
3930
|
+
"strictness": {m: access_guard.builtin_strictness(canon, m)
|
|
3931
|
+
for m in (*access_guard.BUILTIN_MODES, "default")},
|
|
3932
|
+
})
|
|
3933
|
+
projects = []
|
|
3934
|
+
for p in _pm().list_registered():
|
|
3935
|
+
ppath = str(p.get("path") or "")
|
|
3936
|
+
row = {"name": p.get("name") or Path(ppath).name, "path": ppath,
|
|
3937
|
+
"modes": {}, "error": None}
|
|
3938
|
+
try:
|
|
3939
|
+
base = Path(ppath).resolve()
|
|
3940
|
+
if (base / ".c3").is_dir() and base != home:
|
|
3941
|
+
row["modes"] = access_guard._scope_modes("project", ppath)
|
|
3942
|
+
except Exception as e:
|
|
3943
|
+
row["error"] = str(e)
|
|
3944
|
+
if row["modes"] or row["error"]:
|
|
3945
|
+
projects.append(row)
|
|
3946
|
+
from services import builtin_leases
|
|
3947
|
+
return jsonify({"guards": guards, "projects": projects,
|
|
3948
|
+
"leases": builtin_leases.active()})
|
|
3949
|
+
|
|
3950
|
+
|
|
3951
|
+
@app.route("/api/hub/access/builtin/mode", methods=["POST"])
|
|
3952
|
+
def api_hub_access_builtin_mode():
|
|
3953
|
+
"""Set a Tier-1 builtin's mode in the global realm or one project's.
|
|
3954
|
+
|
|
3955
|
+
Body: ``{scope, path?, glob, mode, confirm?}``. A mode at least as strict
|
|
3956
|
+
as the live one needs nothing more. A looser one needs a Desk client
|
|
3957
|
+
token (403 ``needs_human`` without it) and ``confirm`` equal to the glob
|
|
3958
|
+
(400 ``needs_confirmation``). A project is judged against what its
|
|
3959
|
+
agents see today, which is the global mode unless it set its own.
|
|
3960
|
+
"""
|
|
3961
|
+
data = request.get_json(silent=True) or {}
|
|
3962
|
+
scope, project, err = _hub_access_target(data)
|
|
3963
|
+
if err:
|
|
3964
|
+
return err
|
|
3965
|
+
glob = str(data.get("glob") or "")
|
|
3966
|
+
mode = str(data.get("mode") or "").strip()
|
|
3967
|
+
canon = access_guard._norm_builtin(glob)
|
|
3968
|
+
try:
|
|
3969
|
+
new = access_guard.builtin_strictness(canon, mode)
|
|
3970
|
+
live = (access_guard._scope_modes("global") if scope == "global"
|
|
3971
|
+
else access_guard.effective_builtin_modes(project))
|
|
3972
|
+
old = access_guard.builtin_strictness(canon, live.get(canon, "default"))
|
|
3973
|
+
except ValueError as exc:
|
|
3974
|
+
return jsonify({"error": str(exc)}), 400
|
|
3975
|
+
if new < old:
|
|
3976
|
+
if _hub_human() is None:
|
|
3977
|
+
return jsonify({
|
|
3978
|
+
"error": "loosening a built-in guard needs C3 Desk",
|
|
3979
|
+
"needs_human": True,
|
|
3980
|
+
"command": f'c3 access builtin mode "{canon}" {mode}'
|
|
3981
|
+
+ (f' --project --path "{project}"'
|
|
3982
|
+
if scope == "project" else ""),
|
|
3983
|
+
}), 403
|
|
3984
|
+
if access_guard._norm_builtin(data.get("confirm")) != canon:
|
|
3985
|
+
return jsonify({
|
|
3986
|
+
"error": "loosening a built-in guard weakens protection",
|
|
3987
|
+
"needs_confirmation": True, "confirm_with": canon,
|
|
3988
|
+
}), 400
|
|
3989
|
+
try:
|
|
3990
|
+
result = access_guard.set_builtin_mode(canon, mode, scope,
|
|
3991
|
+
project or ".")
|
|
3992
|
+
except ValueError as exc:
|
|
3993
|
+
return jsonify({"error": str(exc)}), 400
|
|
3994
|
+
if result["changed"]:
|
|
3995
|
+
_hub_access_audit(f"builtin_mode_{result['mode']}", result["glob"],
|
|
3996
|
+
"builtin", scope, project)
|
|
3997
|
+
return jsonify({**result, "loosened": new < old})
|
|
3998
|
+
|
|
3999
|
+
|
|
4000
|
+
@app.route("/api/hub/access/builtin/lease", methods=["POST"])
|
|
4001
|
+
def api_hub_access_builtin_lease():
|
|
4002
|
+
"""Loosen a builtin for a while: every session, or one.
|
|
4003
|
+
|
|
4004
|
+
Body: ``{scope, path?, glob, mode, ttl_s, session_id?, confirm}``. A
|
|
4005
|
+
lease only ever loosens, so it always needs a Desk client token and the
|
|
4006
|
+
glob typed back, and a lease no looser than the live mode is a 400
|
|
4007
|
+
rather than a row that would never apply. ``ttl_s`` is 60 s to 8 h.
|
|
4008
|
+
"""
|
|
4009
|
+
from services import builtin_leases
|
|
4010
|
+
data = request.get_json(silent=True) or {}
|
|
4011
|
+
scope, project, err = _hub_access_target(data)
|
|
4012
|
+
if err:
|
|
4013
|
+
return err
|
|
4014
|
+
who = _hub_human()
|
|
4015
|
+
if who is None:
|
|
4016
|
+
return jsonify({"error": "a temporary built-in change needs C3 Desk",
|
|
4017
|
+
"needs_human": True}), 403
|
|
4018
|
+
canon = access_guard._norm_builtin(data.get("glob"))
|
|
4019
|
+
mode = str(data.get("mode") or "").strip()
|
|
4020
|
+
if access_guard._norm_builtin(data.get("confirm")) != canon or not canon:
|
|
4021
|
+
return jsonify({"error": "a temporary change weakens protection",
|
|
4022
|
+
"needs_confirmation": True, "confirm_with": canon}), 400
|
|
4023
|
+
try:
|
|
4024
|
+
live = access_guard.effective_builtin_modes(project or ".") \
|
|
4025
|
+
if scope == "project" else access_guard._scope_modes("global")
|
|
4026
|
+
if access_guard.builtin_strictness(canon, mode) >= \
|
|
4027
|
+
access_guard.builtin_strictness(canon, live.get(canon, "default")):
|
|
4028
|
+
return jsonify({"error": f"{canon} is already {live.get(canon, 'default')}"
|
|
4029
|
+
f" — a {mode} lease would change nothing"}), 400
|
|
4030
|
+
row = builtin_leases.mint(
|
|
4031
|
+
canon, mode, scope=scope, project_path=project or ".",
|
|
4032
|
+
session_id=str(data.get("session_id") or ""),
|
|
4033
|
+
ttl_s=data.get("ttl_s"), created_by=who["client_id"])
|
|
4034
|
+
except ValueError as exc:
|
|
4035
|
+
return jsonify({"error": str(exc)}), 400
|
|
4036
|
+
_hub_access_audit(f"builtin_lease_{mode}", canon, "builtin", scope, project)
|
|
4037
|
+
return jsonify({"lease": row})
|
|
4038
|
+
|
|
4039
|
+
|
|
4040
|
+
@app.route("/api/hub/access/builtin/lease/revoke", methods=["POST"])
|
|
4041
|
+
def api_hub_access_builtin_lease_revoke():
|
|
4042
|
+
"""End a lease now. Tightening, so no token. Body: ``{id}``."""
|
|
4043
|
+
from services import builtin_leases
|
|
4044
|
+
lease_id = str((request.get_json(silent=True) or {}).get("id") or "")
|
|
4045
|
+
gone = builtin_leases.revoke(lease_id) if lease_id else None
|
|
4046
|
+
if gone is None:
|
|
4047
|
+
return jsonify({"error": "unknown or already-expired lease"}), 404
|
|
4048
|
+
_hub_access_audit("builtin_lease_revoke", gone["glob"], "builtin",
|
|
4049
|
+
gone["scope"], gone.get("project_path") or None)
|
|
4050
|
+
return jsonify({"revoked": lease_id})
|
|
4051
|
+
|
|
4052
|
+
|
|
3842
4053
|
# ── Project management: tasks / milestones / notes (v2.45.0) ──────────────
|
|
3843
4054
|
# Direct TaskStore per request (reload-per-op store — no runtime build needed
|
|
3844
4055
|
# for mutations); every write audited to the target project's activity log.
|
{code_context_control-2.146.0 → code_context_control-2.152.0}/cli/hub_ui/components/hub_access.js
RENAMED
|
@@ -19,8 +19,9 @@
|
|
|
19
19
|
// hand — the server enforces that regardless of what this UI believes);
|
|
20
20
|
// - a request that lapsed while the page showed it refreshes to its real
|
|
21
21
|
// status (the decide route answers 409), never silently mints a grant;
|
|
22
|
-
// - rule MUTATION stays on the per-project server and `c3 access
|
|
23
|
-
//
|
|
22
|
+
// - path-rule MUTATION stays on the per-project server and `c3 access`.
|
|
23
|
+
// Builtin guards may be TIGHTENED here; loosening one needs C3 Desk or
|
|
24
|
+
// the CLI, because this page holds no proof that a person clicked.
|
|
24
25
|
|
|
25
26
|
const ACC_KIND_COLOR = (kind) => (
|
|
26
27
|
kind === 'deny' ? T.error : kind === 'mask' ? T.blue
|
|
@@ -387,6 +388,121 @@ function AccRulesPanel({ projects, focus }) {
|
|
|
387
388
|
);
|
|
388
389
|
}
|
|
389
390
|
|
|
391
|
+
// ── Builtin guards ─────────────────────────────────────────────────────────
|
|
392
|
+
// The global mode of every Tier-1 builtin. Picking a stricter mode applies
|
|
393
|
+
// it; picking a looser one is refused by the server without a Desk token,
|
|
394
|
+
// and the panel shows the CLI command instead.
|
|
395
|
+
const ACC_BUILTIN_MODES = ['default', 'deny', 'confirm', 'allow'];
|
|
396
|
+
|
|
397
|
+
function AccBuiltinPanel() {
|
|
398
|
+
const [data, setData] = useState(null);
|
|
399
|
+
const [err, setErr] = useState('');
|
|
400
|
+
const [busy, setBusy] = useState('');
|
|
401
|
+
const [needs, setNeeds] = useState(null);
|
|
402
|
+
|
|
403
|
+
const load = useCallback(async () => {
|
|
404
|
+
try { setData(await api.get('/api/hub/access/builtin')); setErr(''); }
|
|
405
|
+
catch (e) { setErr(apiErr(e)); }
|
|
406
|
+
}, []);
|
|
407
|
+
useEffect(() => { load(); }, [load]);
|
|
408
|
+
usePoll(load, 15000);
|
|
409
|
+
|
|
410
|
+
const setMode = async (g, mode) => {
|
|
411
|
+
setBusy(g.glob); setNeeds(null);
|
|
412
|
+
try {
|
|
413
|
+
await api.post('/api/hub/access/builtin/mode', { scope: 'global', glob: g.glob, mode });
|
|
414
|
+
notify(`${g.glob} is now ${mode} everywhere`, 'ok');
|
|
415
|
+
} catch (e) {
|
|
416
|
+
const body = e && e.payload;
|
|
417
|
+
if (body && body.needs_human) setNeeds({ glob: g.glob, command: body.command });
|
|
418
|
+
else notify(apiErr(e), 'err');
|
|
419
|
+
}
|
|
420
|
+
setBusy('');
|
|
421
|
+
load();
|
|
422
|
+
};
|
|
423
|
+
|
|
424
|
+
const revoke = async (l) => {
|
|
425
|
+
setBusy(l.id);
|
|
426
|
+
try {
|
|
427
|
+
await api.post('/api/hub/access/builtin/lease/revoke', { id: l.id });
|
|
428
|
+
notify(`Ended the ${l.mode} lease on ${l.glob}`, 'ok');
|
|
429
|
+
} catch (e) { notify(apiErr(e), 'err'); }
|
|
430
|
+
setBusy('');
|
|
431
|
+
load();
|
|
432
|
+
};
|
|
433
|
+
|
|
434
|
+
const projects = (data && data.projects) || [];
|
|
435
|
+
const leases = (data && data.leases) || [];
|
|
436
|
+
return (
|
|
437
|
+
<div style={{
|
|
438
|
+
background: T.surface, border: `1px solid ${T.border}`, borderRadius: 10,
|
|
439
|
+
padding: '12px 16px',
|
|
440
|
+
}}>
|
|
441
|
+
<div style={{ display: 'flex', alignItems: 'center', gap: 10, flexWrap: 'wrap' }}>
|
|
442
|
+
<div style={{ fontSize: 12.5, fontWeight: 700, color: T.text }}>Built-in guards</div>
|
|
443
|
+
<span style={{ fontSize: 10.5, color: T.textDim }}>
|
|
444
|
+
global mode — a stricter mode applies here; loosening one needs C3 Desk or the CLI
|
|
445
|
+
</span>
|
|
446
|
+
</div>
|
|
447
|
+
{err && <div style={{ marginTop: 8, fontSize: 11.5, color: T.error }}>{err}</div>}
|
|
448
|
+
{needs && (
|
|
449
|
+
<div style={{ marginTop: 8, fontSize: 11.5, color: T.warn }}>
|
|
450
|
+
Loosening <span className="mono">{needs.glob}</span> needs C3 Desk, or run:{' '}
|
|
451
|
+
<span className="mono" style={{ color: T.text }}>{needs.command}</span>
|
|
452
|
+
</div>
|
|
453
|
+
)}
|
|
454
|
+
{data && (
|
|
455
|
+
<div style={{ marginTop: 10, display: 'grid', gridTemplateColumns: 'minmax(0,1fr) auto', gap: '4px 12px', alignItems: 'center' }}>
|
|
456
|
+
{data.guards.map(g => (
|
|
457
|
+
<React.Fragment key={g.glob}>
|
|
458
|
+
<span className="mono" style={{ fontSize: 11.5, color: T.text, overflow: 'hidden', textOverflow: 'ellipsis' }}>{g.glob}</span>
|
|
459
|
+
<select value={g.global} disabled={busy === g.glob}
|
|
460
|
+
onChange={e => setMode(g, e.target.value)}
|
|
461
|
+
style={{
|
|
462
|
+
background: T.surfaceAlt, color: g.global === 'default' ? T.textMuted : T.warn,
|
|
463
|
+
border: `1px solid ${T.border}`, borderRadius: 6, fontSize: 11.5, padding: '2px 6px',
|
|
464
|
+
}}>
|
|
465
|
+
{ACC_BUILTIN_MODES.map(m => <option key={m} value={m}>{m}</option>)}
|
|
466
|
+
</select>
|
|
467
|
+
</React.Fragment>
|
|
468
|
+
))}
|
|
469
|
+
</div>
|
|
470
|
+
)}
|
|
471
|
+
{leases.length > 0 && (
|
|
472
|
+
<div style={{ marginTop: 10, display: 'flex', flexDirection: 'column', gap: 4 }}>
|
|
473
|
+
<div style={{ fontSize: 10.5, fontWeight: 700, letterSpacing: 1, textTransform: 'uppercase', color: T.warn }}>
|
|
474
|
+
temporary changes
|
|
475
|
+
</div>
|
|
476
|
+
{leases.map(l => (
|
|
477
|
+
<div key={l.id} style={{ display: 'flex', alignItems: 'center', gap: 8, fontSize: 11.5 }}>
|
|
478
|
+
<span className="mono" style={{ color: T.text }}>{l.glob}</span>
|
|
479
|
+
<span style={{ color: T.warn }}>{l.mode}</span>
|
|
480
|
+
<span style={{ color: T.textMuted }}>
|
|
481
|
+
{l.scope === 'project' ? l.project_path : 'all projects'}
|
|
482
|
+
{' · '}{l.session_id ? <>session <span className="mono">{l.session_id.slice(0, 8)}</span></> : 'all sessions'}
|
|
483
|
+
{' · '}ends in {accExpiresIn(l.expires_at) || '—'}
|
|
484
|
+
</span>
|
|
485
|
+
<div style={{ flex: 1 }} />
|
|
486
|
+
<Btn variant="ghost" disabled={busy === l.id} onClick={() => revoke(l)}>Revoke</Btn>
|
|
487
|
+
</div>
|
|
488
|
+
))}
|
|
489
|
+
</div>
|
|
490
|
+
)}
|
|
491
|
+
{projects.length > 0 && (
|
|
492
|
+
<div style={{ marginTop: 8, fontSize: 11, color: T.textDim }}>
|
|
493
|
+
Set per project:{' '}
|
|
494
|
+
{projects.map(p => (
|
|
495
|
+
<span key={p.path} className="mono" style={{ marginRight: 10 }}>
|
|
496
|
+
{p.name}: {p.error ? `unreadable (${p.error})`
|
|
497
|
+
: Object.entries(p.modes).map(([g, m]) => `${g}=${m}`).join(', ')}
|
|
498
|
+
</span>
|
|
499
|
+
))}
|
|
500
|
+
</div>
|
|
501
|
+
)}
|
|
502
|
+
</div>
|
|
503
|
+
);
|
|
504
|
+
}
|
|
505
|
+
|
|
390
506
|
// ── Active grants ──────────────────────────────────────────────────────────
|
|
391
507
|
// A rule grant can authorise many calls over hours. The only other place it
|
|
392
508
|
// shows up is a line in the agent's own transcript, which is the wrong place
|
|
@@ -762,6 +878,7 @@ function HubAccess({ projects }) {
|
|
|
762
878
|
)}
|
|
763
879
|
|
|
764
880
|
<AccGrantsPanel projects={projects} />
|
|
881
|
+
<AccBuiltinPanel />
|
|
765
882
|
<AccRulesPanel projects={projects} focus={ruleFocus} />
|
|
766
883
|
{confirmSpec && (
|
|
767
884
|
<CredConfirm spec={confirmSpec} onClose={() => setConfirmSpec(null)} />
|
{code_context_control-2.146.0 → code_context_control-2.152.0}/cli/hub_ui/components/modals.js
RENAMED
|
@@ -528,24 +528,41 @@ function ReparentModal({ project, projects, onClose, onChanged }) {
|
|
|
528
528
|
|
|
529
529
|
// ── IDE picker ─────────────────────────────────────────────────
|
|
530
530
|
// POST /api/projects/launch-ide {path, ide, custom_cmd?}
|
|
531
|
+
// The command is editable per project (stored as ide_cmd via
|
|
532
|
+
// /api/projects/update) so an agent started through a wrapper — `yep` rather
|
|
533
|
+
// than `claude` — launches from the card too, not just from here.
|
|
531
534
|
function IdePickerModal({ project, onClose, onChanged }) {
|
|
532
535
|
const known = IDE_OPTIONS.some(o => o.id === (project && project.ide));
|
|
533
536
|
const [selected, setSelected] = useState(known ? project.ide : 'claude-code');
|
|
534
|
-
const
|
|
537
|
+
const savedCmd = ((project && project.ide_cmd) || '').trim();
|
|
538
|
+
const [customCmd, setCustomCmd] = useState(savedCmd);
|
|
539
|
+
const [remember, setRemember] = useState(!!savedCmd);
|
|
535
540
|
const [busy, setBusy] = useState(false);
|
|
536
541
|
|
|
542
|
+
const stockCmd = (id) => {
|
|
543
|
+
const opt = IDE_OPTIONS.find(o => o.id === id);
|
|
544
|
+
return opt && opt.cmd !== '...' ? opt.cmd : '';
|
|
545
|
+
};
|
|
546
|
+
const effectiveCmd = customCmd.trim() || stockCmd(selected);
|
|
547
|
+
|
|
537
548
|
const launch = async () => {
|
|
538
|
-
|
|
549
|
+
const cmd = customCmd.trim();
|
|
550
|
+
if (selected === 'custom' && !cmd) {
|
|
539
551
|
notify('Enter a custom command first.', 'err');
|
|
540
552
|
return;
|
|
541
553
|
}
|
|
542
554
|
setBusy(true);
|
|
543
555
|
try {
|
|
556
|
+
// Persist first: the project card launches with no command of its own.
|
|
557
|
+
const wanted = remember ? cmd : '';
|
|
558
|
+
if (wanted !== savedCmd) {
|
|
559
|
+
await api.post('/api/projects/update', { path: project.path, ide_cmd: wanted });
|
|
560
|
+
}
|
|
544
561
|
await api.post('/api/projects/launch-ide', {
|
|
545
|
-
path: project.path, ide: selected,
|
|
546
|
-
custom_cmd: selected === 'custom' ? customCmd.trim() : '',
|
|
562
|
+
path: project.path, ide: selected, custom_cmd: cmd,
|
|
547
563
|
});
|
|
548
|
-
notify(`Launched ${ideLabel(selected)} in ${project.name || project.path}`);
|
|
564
|
+
notify(`Launched ${ideLabel(selected)} (${effectiveCmd}) in ${project.name || project.path}`);
|
|
565
|
+
if (onChanged) onChanged();
|
|
549
566
|
onClose();
|
|
550
567
|
} catch (e) {
|
|
551
568
|
notify(`Launch failed: ${e.message}`, 'err');
|
|
@@ -575,13 +592,18 @@ function IdePickerModal({ project, onClose, onChanged }) {
|
|
|
575
592
|
);
|
|
576
593
|
})}
|
|
577
594
|
</div>
|
|
578
|
-
|
|
579
|
-
<
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
595
|
+
<div>
|
|
596
|
+
<MdlLabel>Command{selected === 'custom' ? '' : ' (leave blank for the default)'}</MdlLabel>
|
|
597
|
+
<input value={customCmd} onChange={e => setCustomCmd(e.target.value)}
|
|
598
|
+
placeholder={selected === 'custom' ? 'e.g. nvim .' : `${stockCmd(selected)} — override with e.g. yep`}
|
|
599
|
+
className="mono" style={mdlInputStyle()} />
|
|
600
|
+
<label style={{ display: 'flex', alignItems: 'center', gap: 6, marginTop: 6,
|
|
601
|
+
fontSize: 11, color: T.textMuted, cursor: 'pointer' }}>
|
|
602
|
+
<input type="checkbox" checked={remember}
|
|
603
|
+
onChange={e => setRemember(e.target.checked)} />
|
|
604
|
+
Remember for this project (used by the card's launch button too)
|
|
605
|
+
</label>
|
|
606
|
+
</div>
|
|
585
607
|
<MdlFooter>
|
|
586
608
|
<Btn variant="ghost" onClick={onClose}>Cancel</Btn>
|
|
587
609
|
<Btn onClick={launch} disabled={busy}>
|
|
@@ -14,6 +14,7 @@ function SettingsModal({ onClose, onChanged }) {
|
|
|
14
14
|
const [port, setPort] = useState('');
|
|
15
15
|
const [autoBrowser, setAutoBrowser] = useState(true);
|
|
16
16
|
const [oracleUrl, setOracleUrl] = useState('');
|
|
17
|
+
const [agentCmd, setAgentCmd] = useState(''); // ide_cmds['claude-code']
|
|
17
18
|
const [cacheSize, setCacheSize] = useState(8);
|
|
18
19
|
const [saving, setSaving] = useState(false);
|
|
19
20
|
const [svc, setSvc] = useState(null); // hub: {installed, running, method, port, log_path} | {error}
|
|
@@ -51,6 +52,7 @@ function SettingsModal({ onClose, onChanged }) {
|
|
|
51
52
|
setPort(d.port || 3330);
|
|
52
53
|
setAutoBrowser(!!d.auto_open_browser);
|
|
53
54
|
setOracleUrl(d.oracle_url || '');
|
|
55
|
+
setAgentCmd(((d.ide_cmds || {})['claude-code']) || '');
|
|
54
56
|
setCacheSize(d.runtime_cache_size || 8);
|
|
55
57
|
} catch {
|
|
56
58
|
notify('Could not load hub config', 'err');
|
|
@@ -70,9 +72,14 @@ function SettingsModal({ onClose, onChanged }) {
|
|
|
70
72
|
const cache = Math.max(1, parseInt(cacheSize, 10) || 8);
|
|
71
73
|
setSaving(true);
|
|
72
74
|
try {
|
|
75
|
+
// Blank restores the stock `claude`; other IDE overrides are left alone.
|
|
76
|
+
const ideCmds = { ...((cfg && cfg.ide_cmds) || {}) };
|
|
77
|
+
if (agentCmd.trim()) ideCmds['claude-code'] = agentCmd.trim();
|
|
78
|
+
else delete ideCmds['claude-code'];
|
|
73
79
|
await api.post('/api/hub/config', {
|
|
74
80
|
port: portVal, auto_open_browser: autoBrowser,
|
|
75
81
|
oracle_url: oracleUrl.trim(), runtime_cache_size: cache,
|
|
82
|
+
ide_cmds: ideCmds,
|
|
76
83
|
});
|
|
77
84
|
const portChanged = cfg && portVal !== cfg.port;
|
|
78
85
|
notify(portChanged
|
|
@@ -222,6 +229,10 @@ function SettingsModal({ onClose, onChanged }) {
|
|
|
222
229
|
<input type="number" value={cacheSize} onChange={e => setCacheSize(e.target.value)}
|
|
223
230
|
min={1} className="mono" style={inputStyle(110)} />
|
|
224
231
|
), 'Max project runtimes kept warm for drill-in and global search.')}
|
|
232
|
+
{fieldRow('Agent command', (
|
|
233
|
+
<input value={agentCmd} onChange={e => setAgentCmd(e.target.value)}
|
|
234
|
+
placeholder="claude" className="mono" style={inputStyle(220)} />
|
|
235
|
+
), 'Default command for "Claude Code CLI" launches — e.g. yep for a wrapper script. A project can override it in Open in IDE.')}
|
|
225
236
|
{fieldRow('Oracle URL', (
|
|
226
237
|
<input value={oracleUrl} onChange={e => setOracleUrl(e.target.value)}
|
|
227
238
|
placeholder="http://localhost:3331" className="mono" style={inputStyle(220)} />
|