code-context-control 2.57.1__tar.gz → 2.58.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.57.1/code_context_control.egg-info → code_context_control-2.58.0}/PKG-INFO +41 -2
- {code_context_control-2.57.1 → code_context_control-2.58.0}/README.md +40 -1
- {code_context_control-2.57.1 → code_context_control-2.58.0}/cli/c3.py +147 -2
- {code_context_control-2.57.1 → code_context_control-2.58.0}/cli/commands/parser.py +42 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/cli/hub_server.py +30 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/cli/hub_ui/components/drill_panel.js +2 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/cli/hub_ui/components/drill_views.js +50 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/cli/mcp_server.py +59 -4
- {code_context_control-2.57.1 → code_context_control-2.58.0}/cli/server.py +147 -0
- code_context_control-2.58.0/cli/tools/credentials.py +239 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/cli/tools/project.py +5 -1
- {code_context_control-2.57.1 → code_context_control-2.58.0}/cli/tools/shell.py +55 -5
- {code_context_control-2.57.1 → code_context_control-2.58.0}/cli/ui/app.js +4 -0
- code_context_control-2.58.0/cli/ui/components/credentials.js +365 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/cli/ui/icons.js +2 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0/code_context_control.egg-info}/PKG-INFO +41 -2
- {code_context_control-2.57.1 → code_context_control-2.58.0}/code_context_control.egg-info/SOURCES.txt +9 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/pyproject.toml +1 -1
- {code_context_control-2.57.1 → code_context_control-2.58.0}/services/claude_md.py +1 -0
- code_context_control-2.58.0/services/credential_store.py +638 -0
- code_context_control-2.58.0/tests/test_credential_store.py +270 -0
- code_context_control-2.58.0/tests/test_credentials_routes.py +175 -0
- code_context_control-2.58.0/tests/test_credentials_tool.py +202 -0
- code_context_control-2.58.0/tests/test_creds_cli_smoke.py +150 -0
- code_context_control-2.58.0/tests/test_hub_credentials_route.py +86 -0
- code_context_control-2.58.0/tests/test_shell_creds.py +172 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/tests/test_tool_registry.py +4 -1
- {code_context_control-2.57.1 → code_context_control-2.58.0}/LICENSE +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/cli/__init__.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/cli/_hook_utils.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/cli/commands/__init__.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/cli/commands/common.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/cli/docs.html +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/cli/edits.html +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/cli/guide/bitbucket.html +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/cli/guide/getting-started.html +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/cli/guide/index.html +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/cli/guide/oracle.html +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/cli/guide/shared.css +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/cli/guide/tools.html +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/cli/guide/workflow.html +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/cli/hook_artifact.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/cli/hook_auto_snapshot.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/cli/hook_c3_signal.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/cli/hook_c3read.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/cli/hook_dispatch.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/cli/hook_edit_ledger.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/cli/hook_edit_unlock.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/cli/hook_filter.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/cli/hook_ghost_files.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/cli/hook_pretool_enforce.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/cli/hook_prompt_recall.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/cli/hook_read.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/cli/hook_session_stats.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/cli/hook_terse_advisor.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/cli/hub.html +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/cli/hub_ui/app.js +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/cli/hub_ui/components/add_project.js +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/cli/hub_ui/components/config_editor.js +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/cli/hub_ui/components/drill_artifacts.js +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/cli/hub_ui/components/drill_health.js +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/cli/hub_ui/components/drill_subprojects.js +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/cli/hub_ui/components/drill_tasks.js +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/cli/hub_ui/components/global_search.js +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/cli/hub_ui/components/mcp_manager.js +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/cli/hub_ui/components/modals.js +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/cli/hub_ui/components/project_card.js +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/cli/hub_ui/components/project_tree.js +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/cli/hub_ui/components/session_drawer.js +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/cli/hub_ui/components/settings_modal.js +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/cli/hub_ui/components/sidebar.js +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/cli/hub_ui/components/summary_bar.js +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/cli/hub_ui/components/task_board.js +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/cli/hub_ui/components/toasts.js +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/cli/hub_ui/components/topbar.js +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/cli/hub_ui/state.js +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/cli/hub_ui.html +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/cli/mcp_proxy.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/cli/progress.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/cli/tools/__init__.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/cli/tools/_helpers.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/cli/tools/agent.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/cli/tools/artifacts.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/cli/tools/bitbucket.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/cli/tools/compress.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/cli/tools/delegate.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/cli/tools/edit.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/cli/tools/edits.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/cli/tools/federate.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/cli/tools/filter.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/cli/tools/impact.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/cli/tools/jira.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/cli/tools/memory.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/cli/tools/read.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/cli/tools/search.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/cli/tools/session.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/cli/tools/status.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/cli/tools/tasks.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/cli/tools/validate.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/cli/ui/api.js +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/cli/ui/components/bitbucket.js +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/cli/ui/components/chat.js +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/cli/ui/components/dashboard.js +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/cli/ui/components/edits.js +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/cli/ui/components/instructions.js +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/cli/ui/components/jira.js +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/cli/ui/components/memory.js +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/cli/ui/components/sessions.js +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/cli/ui/components/settings.js +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/cli/ui/components/sidebar.js +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/cli/ui/components/tasks.js +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/cli/ui/pm_shared.js +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/cli/ui/shared.js +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/cli/ui/theme.js +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/cli/ui.html +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/cli/ui_legacy.html +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/cli/ui_nano.html +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/code_context_control.egg-info/dependency_links.txt +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/code_context_control.egg-info/entry_points.txt +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/code_context_control.egg-info/requires.txt +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/code_context_control.egg-info/top_level.txt +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/core/__init__.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/core/config.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/core/ide.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/core/mcp_toml.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/core/web_security.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/oracle/__init__.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/oracle/config.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/oracle/mcp_oracle.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/oracle/oracle_server.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/oracle/oracle_ui.html +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/oracle/services/__init__.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/oracle/services/activity_reporter.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/oracle/services/api_auth.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/oracle/services/c3_bridge.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/oracle/services/chat_engine.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/oracle/services/chat_store.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/oracle/services/cross_memory.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/oracle/services/federated_graph.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/oracle/services/health_checker.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/oracle/services/insight_engine.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/oracle/services/local_session.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/oracle/services/memory_reader.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/oracle/services/memory_writer.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/oracle/services/project_scanner.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/oracle/services/review_agent.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/oracle/services/tool_executor.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/oracle/services/tool_registry.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/oracle/ui/activity.js +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/oracle/ui/agents.js +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/oracle/ui/app.js +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/oracle/ui/busy.js +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/oracle/ui/chat/conversations.js +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/oracle/ui/chat/input.js +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/oracle/ui/chat/markdown.js +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/oracle/ui/chat/send.js +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/oracle/ui/chat/stream_renderer.js +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/oracle/ui/chat/toolbar.js +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/oracle/ui/core.js +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/oracle/ui/crossgraph.js +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/oracle/ui/header.js +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/oracle/ui/insights.js +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/oracle/ui/projects.js +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/oracle/ui/settings.js +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/oracle/ui/suggestions.js +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/oracle/ui/theme_tabs.js +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/services/__init__.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/services/activity_log.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/services/agent_base.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/services/agents.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/services/artifact_defs.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/services/artifact_store.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/services/auto_memory.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/services/bench/__init__.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/services/bench/external/__init__.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/services/bench/external/aider_polyglot.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/services/bench/external/swe_bench.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/services/benchmark_dashboard.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/services/bitbucket_client.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/services/bitbucket_credentials.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/services/circuit_breaker.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/services/compressor.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/services/context_snapshot.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/services/conversation_store.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/services/doc_index.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/services/e2e_benchmark.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/services/e2e_evaluator.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/services/e2e_tasks.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/services/edit_ledger.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/services/embedding_index.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/services/error_reporting.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/services/file_memory.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/services/git_context.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/services/hub_service.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/services/indexer.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/services/jira_client.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/services/jira_cloud.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/services/jira_credentials.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/services/jira_data_center.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/services/jira_links.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/services/memory.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/services/memory_consolidator.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/services/memory_distiller.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/services/memory_graph.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/services/memory_grounder.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/services/memory_queue.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/services/memory_scorer.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/services/metrics.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/services/notifications.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/services/ollama_bridge.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/services/ollama_client.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/services/ollama_credentials.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/services/output_filter.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/services/parser.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/services/project_manager.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/services/project_runtime.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/services/protocol.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/services/proxy_state.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/services/retention.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/services/retrieval_broker.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/services/router.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/services/runtime.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/services/scanner.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/services/session_benchmark.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/services/session_manager.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/services/session_preloader.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/services/subprojects.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/services/task_store.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/services/telemetry.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/services/text_index.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/services/time_tracker.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/services/tool_classifier.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/services/transcript_index.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/services/validation_cache.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/services/vector_store.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/services/watcher.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/services/win_subprocess.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/setup.cfg +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/tests/test_activity_reporter.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/tests/test_aider_polyglot.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/tests/test_antigravity_transition.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/tests/test_artifact_store.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/tests/test_artifact_tool.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/tests/test_bitbucket_cli_smoke.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/tests/test_bitbucket_client.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/tests/test_bitbucket_config_fallback.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/tests/test_bitbucket_credentials.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/tests/test_bitbucket_tool.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/tests/test_c3_bridge_project_artifacts.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/tests/test_c3_shell.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/tests/test_circuit_breaker.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/tests/test_claude_md_merge.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/tests/test_cli_smoke.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/tests/test_compressor_large_file.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/tests/test_delegate_cascade.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/tests/test_e2e_benchmark.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/tests/test_edit_ledger_hook.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/tests/test_edit_normalization.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/tests/test_enforcement_flip.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/tests/test_federated_graph.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/tests/test_filter_backoff.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/tests/test_ghost_files.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/tests/test_ghost_generation.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/tests/test_git_branch_awareness.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/tests/test_hook_dispatch.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/tests/test_hook_pretool_enforce.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/tests/test_hook_prompt_recall.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/tests/test_hook_smoke.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/tests/test_hook_state.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/tests/test_hook_utf8_stdio.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/tests/test_hub_inspect_api.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/tests/test_hub_server_smoke.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/tests/test_hub_subproject_links.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/tests/test_init_scan.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/tests/test_install_mcp_entrypoint.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/tests/test_jira_cli_smoke.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/tests/test_jira_client.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/tests/test_jira_config_fallback.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/tests/test_jira_credentials.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/tests/test_jira_links.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/tests/test_jira_routes.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/tests/test_jira_tool.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/tests/test_lazy_store_init.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/tests/test_mcp_host_guard.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/tests/test_mcp_memory_timeout.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/tests/test_mcp_server_smoke.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/tests/test_mcp_toml.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/tests/test_memory_distiller.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/tests/test_memory_graph_api.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/tests/test_memory_queue.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/tests/test_memory_system.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/tests/test_notification_dedup.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/tests/test_notification_discipline.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/tests/test_ollama_credentials.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/tests/test_oracle_api_auth.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/tests/test_oracle_apikey_api.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/tests/test_oracle_c3_bridge.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/tests/test_oracle_chat_engine.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/tests/test_oracle_discovery_api.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/tests/test_oracle_local_auth.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/tests/test_oracle_ollama_bridge.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/tests/test_oracle_scanner_cache.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/tests/test_oracle_security_fixes.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/tests/test_oracle_subproject_awareness.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/tests/test_oracle_ui_bundle.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/tests/test_output_filter.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/tests/test_permissions.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/tests/test_pm_api.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/tests/test_project_manager.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/tests/test_project_manager_merge.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/tests/test_project_tool.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/tests/test_read_coercion.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/tests/test_read_edit_parity.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/tests/test_related_facts.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/tests/test_response_boilerplate.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/tests/test_retention.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/tests/test_review_digest.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/tests/test_service_durability.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/tests/test_session_benchmark.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/tests/test_session_budget.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/tests/test_shell_robustness.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/tests/test_subproject_exclusion.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/tests/test_subproject_federation.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/tests/test_subprojects.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/tests/test_swe_bench.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/tests/test_task_store.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/tests/test_task_tool.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/tests/test_time_tracker.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/tests/test_token_telemetry.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/tests/test_upgrade_and_version.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/tests/test_validate.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/tests/test_version_sync.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/tests/test_web_security.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/tests/test_windows_reliability.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/tui/__init__.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/tui/backend.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/tui/main.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/tui/screens/__init__.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/tui/screens/benchmark_view.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/tui/screens/claudemd_view.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/tui/screens/compress_view.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/tui/screens/index_view.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/tui/screens/init_view.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/tui/screens/mcp_view.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/tui/screens/optimize_view.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/tui/screens/pipe_view.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/tui/screens/projects_view.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/tui/screens/search_view.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/tui/screens/session_view.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/tui/screens/stats.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/tui/screens/ui_view.py +0 -0
- {code_context_control-2.57.1 → code_context_control-2.58.0}/tui/theme.tcss +0 -0
{code_context_control-2.57.1/code_context_control.egg-info → code_context_control-2.58.0}/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: code-context-control
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.58.0
|
|
4
4
|
Summary: Local code-intelligence layer for AI coding tools (Claude Code, Codex, Copilot, Cursor, Antigravity). Retrieve less, read less, edit safer — version the configs that shape your agent (CLAUDE.md, skills, hooks, MCP), and manage multi-project + sub-project hierarchies from a local hub.
|
|
5
5
|
Author-email: Dimitri Tselenchuk <dtselenc@gmail.com>
|
|
6
6
|
License-Expression: Apache-2.0
|
|
@@ -283,6 +283,7 @@ C3 exposes 18 tools as a native MCP server. Your IDE calls them directly:
|
|
|
283
283
|
| `c3_edits` | Edit-ledger queries + version diffs + restore points + per-branch filter |
|
|
284
284
|
| `c3_bitbucket` | Bitbucket Data Center integration — PRs, branches, builds, repo admin (v2.30.0) |
|
|
285
285
|
| `c3_jira` | Jira integration — Cloud + Data Center: JQL search, issues, transitions, My Work board (v2.56.0) |
|
|
286
|
+
| `c3_credentials` | Credential vault — named secrets (global + per-project), injection-first: agents use them by name, values never enter model context (v2.58.0) |
|
|
286
287
|
| `c3_project` | Cross-project — discover & operate on other c3-installed projects; guarded writes (v2.31.0) |
|
|
287
288
|
| `c3_task` | Durable per-project PM — tasks with dependencies & subtasks, milestones, decision notes, event history, health reports, and auto+manual time tracking (v2.53.0) |
|
|
288
289
|
| `c3_artifacts` | Agent-config tracking — version history, diff & restore for CLAUDE.md, settings/hooks, MCP configs, skills (v2.46.0) |
|
|
@@ -291,7 +292,7 @@ On Windows, `c3_shell` uses Git Bash when available. Git Bash does not bundle
|
|
|
291
292
|
optional utilities such as `jq`; use `python -m json.tool` for portable JSON
|
|
292
293
|
formatting, or install `jq` separately when filter expressions are required.
|
|
293
294
|
|
|
294
|
-
Every tool is **read-only safe in plan mode** (except `c3_edit`, `c3_shell`, `c3_artifacts(action='restore')`, and write actions on `c3_bitbucket` / `c3_jira` / `c3_project` / `c3_task`).
|
|
295
|
+
Every tool is **read-only safe in plan mode** (except `c3_edit`, `c3_shell`, `c3_artifacts(action='restore')`, and write actions on `c3_bitbucket` / `c3_jira` / `c3_credentials` / `c3_project` / `c3_task`).
|
|
295
296
|
|
|
296
297
|
### Bitbucket Data Center / Server (v2.30.0)
|
|
297
298
|
|
|
@@ -319,6 +320,44 @@ it has no active account C3 falls back to the global `~/.c3/config.json`. So a
|
|
|
319
320
|
single `login --global` (or any login done from your home directory) is reusable
|
|
320
321
|
across every C3 project — the PAT always lives in the OS keyring, never on disk.
|
|
321
322
|
|
|
323
|
+
### Credential vault (v2.58.0)
|
|
324
|
+
|
|
325
|
+
`c3_credentials` gives agents a protected, user-managed place for API keys,
|
|
326
|
+
tokens, and `.env`-style values — **global** (`~/.c3`, every project) or
|
|
327
|
+
**per-project** (`.c3`, shadows the global name). Values live in the **OS
|
|
328
|
+
keyring** (large values in a Fernet-encrypted `.c3/secrets.enc` whose master
|
|
329
|
+
key lives in the keyring) — never in config files, and *never in the model's
|
|
330
|
+
context*: the agent addresses secrets by name and C3 decodes them only at the
|
|
331
|
+
subprocess boundary.
|
|
332
|
+
|
|
333
|
+
```bash
|
|
334
|
+
# Store a secret for this project (value prompted, masked)
|
|
335
|
+
c3 creds set OPENAI_KEY --desc "OpenAI billing key"
|
|
336
|
+
|
|
337
|
+
# ...or globally for every C3 project
|
|
338
|
+
c3 creds set NPM_TOKEN --global
|
|
339
|
+
|
|
340
|
+
# Bulk-import an existing .env; list what the agent can see
|
|
341
|
+
c3 creds import .env
|
|
342
|
+
c3 creds list
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
The agent then runs commands *with* the secret but without ever seeing it:
|
|
346
|
+
|
|
347
|
+
```
|
|
348
|
+
c3_shell(cmd='npm publish', env_creds='NPM_TOKEN') # injected as env var
|
|
349
|
+
c3_shell(cmd='curl -H "Authorization: Bearer {{cred:OPENAI_KEY}}" …') # expanded server-side
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
Echoed values are auto-redacted from output (`env` dumps come back as
|
|
353
|
+
`[cred:NAME]`), every use is ledger-logged by name, and `reveal` — the only
|
|
354
|
+
action that returns a value — is disabled per entry until you flip
|
|
355
|
+
`agent_readable` in the **Credentials UI tab** or via
|
|
356
|
+
`c3 creds set NAME --agent-readable`. A hostile repo config can't siphon your
|
|
357
|
+
global secrets (realm-atomic resolution, tested), cross-project shells run
|
|
358
|
+
with credentials disabled, and the vault is hard-excluded from the Oracle
|
|
359
|
+
Discovery API.
|
|
360
|
+
|
|
322
361
|
### Jira — Cloud + Data Center (v2.56.0)
|
|
323
362
|
|
|
324
363
|
`c3_jira` connects to Jira Cloud (REST v3, email + API token) or self-hosted
|
|
@@ -220,6 +220,7 @@ C3 exposes 18 tools as a native MCP server. Your IDE calls them directly:
|
|
|
220
220
|
| `c3_edits` | Edit-ledger queries + version diffs + restore points + per-branch filter |
|
|
221
221
|
| `c3_bitbucket` | Bitbucket Data Center integration — PRs, branches, builds, repo admin (v2.30.0) |
|
|
222
222
|
| `c3_jira` | Jira integration — Cloud + Data Center: JQL search, issues, transitions, My Work board (v2.56.0) |
|
|
223
|
+
| `c3_credentials` | Credential vault — named secrets (global + per-project), injection-first: agents use them by name, values never enter model context (v2.58.0) |
|
|
223
224
|
| `c3_project` | Cross-project — discover & operate on other c3-installed projects; guarded writes (v2.31.0) |
|
|
224
225
|
| `c3_task` | Durable per-project PM — tasks with dependencies & subtasks, milestones, decision notes, event history, health reports, and auto+manual time tracking (v2.53.0) |
|
|
225
226
|
| `c3_artifacts` | Agent-config tracking — version history, diff & restore for CLAUDE.md, settings/hooks, MCP configs, skills (v2.46.0) |
|
|
@@ -228,7 +229,7 @@ On Windows, `c3_shell` uses Git Bash when available. Git Bash does not bundle
|
|
|
228
229
|
optional utilities such as `jq`; use `python -m json.tool` for portable JSON
|
|
229
230
|
formatting, or install `jq` separately when filter expressions are required.
|
|
230
231
|
|
|
231
|
-
Every tool is **read-only safe in plan mode** (except `c3_edit`, `c3_shell`, `c3_artifacts(action='restore')`, and write actions on `c3_bitbucket` / `c3_jira` / `c3_project` / `c3_task`).
|
|
232
|
+
Every tool is **read-only safe in plan mode** (except `c3_edit`, `c3_shell`, `c3_artifacts(action='restore')`, and write actions on `c3_bitbucket` / `c3_jira` / `c3_credentials` / `c3_project` / `c3_task`).
|
|
232
233
|
|
|
233
234
|
### Bitbucket Data Center / Server (v2.30.0)
|
|
234
235
|
|
|
@@ -256,6 +257,44 @@ it has no active account C3 falls back to the global `~/.c3/config.json`. So a
|
|
|
256
257
|
single `login --global` (or any login done from your home directory) is reusable
|
|
257
258
|
across every C3 project — the PAT always lives in the OS keyring, never on disk.
|
|
258
259
|
|
|
260
|
+
### Credential vault (v2.58.0)
|
|
261
|
+
|
|
262
|
+
`c3_credentials` gives agents a protected, user-managed place for API keys,
|
|
263
|
+
tokens, and `.env`-style values — **global** (`~/.c3`, every project) or
|
|
264
|
+
**per-project** (`.c3`, shadows the global name). Values live in the **OS
|
|
265
|
+
keyring** (large values in a Fernet-encrypted `.c3/secrets.enc` whose master
|
|
266
|
+
key lives in the keyring) — never in config files, and *never in the model's
|
|
267
|
+
context*: the agent addresses secrets by name and C3 decodes them only at the
|
|
268
|
+
subprocess boundary.
|
|
269
|
+
|
|
270
|
+
```bash
|
|
271
|
+
# Store a secret for this project (value prompted, masked)
|
|
272
|
+
c3 creds set OPENAI_KEY --desc "OpenAI billing key"
|
|
273
|
+
|
|
274
|
+
# ...or globally for every C3 project
|
|
275
|
+
c3 creds set NPM_TOKEN --global
|
|
276
|
+
|
|
277
|
+
# Bulk-import an existing .env; list what the agent can see
|
|
278
|
+
c3 creds import .env
|
|
279
|
+
c3 creds list
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
The agent then runs commands *with* the secret but without ever seeing it:
|
|
283
|
+
|
|
284
|
+
```
|
|
285
|
+
c3_shell(cmd='npm publish', env_creds='NPM_TOKEN') # injected as env var
|
|
286
|
+
c3_shell(cmd='curl -H "Authorization: Bearer {{cred:OPENAI_KEY}}" …') # expanded server-side
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
Echoed values are auto-redacted from output (`env` dumps come back as
|
|
290
|
+
`[cred:NAME]`), every use is ledger-logged by name, and `reveal` — the only
|
|
291
|
+
action that returns a value — is disabled per entry until you flip
|
|
292
|
+
`agent_readable` in the **Credentials UI tab** or via
|
|
293
|
+
`c3 creds set NAME --agent-readable`. A hostile repo config can't siphon your
|
|
294
|
+
global secrets (realm-atomic resolution, tested), cross-project shells run
|
|
295
|
+
with credentials disabled, and the vault is hard-excluded from the Oracle
|
|
296
|
+
Discovery API.
|
|
297
|
+
|
|
259
298
|
### Jira — Cloud + Data Center (v2.56.0)
|
|
260
299
|
|
|
261
300
|
`c3_jira` connects to Jira Cloud (REST v3, email + API token) or self-hosted
|
|
@@ -92,7 +92,7 @@ console = Console() if HAS_RICH else None
|
|
|
92
92
|
# Config
|
|
93
93
|
CONFIG_DIR = ".c3"
|
|
94
94
|
CONFIG_FILE = ".c3/config.json"
|
|
95
|
-
__version__ = "2.
|
|
95
|
+
__version__ = "2.58.0"
|
|
96
96
|
|
|
97
97
|
|
|
98
98
|
def _command_deps() -> CommandDeps:
|
|
@@ -248,7 +248,7 @@ _C3_MCP_ALLOW = [
|
|
|
248
248
|
"mcp__c3__c3_memory", "mcp__c3__c3_validate", "mcp__c3__c3_edit",
|
|
249
249
|
"mcp__c3__c3_agent", "mcp__c3__c3_delegate", "mcp__c3__c3_edits",
|
|
250
250
|
"mcp__c3__c3_impact", "mcp__c3__c3_shell", "mcp__c3__c3_bitbucket",
|
|
251
|
-
"mcp__c3__c3_jira",
|
|
251
|
+
"mcp__c3__c3_jira", "mcp__c3__c3_credentials",
|
|
252
252
|
"mcp__c3__c3_project", "mcp__c3__c3_task", "mcp__c3__c3_artifacts",
|
|
253
253
|
]
|
|
254
254
|
|
|
@@ -5738,6 +5738,150 @@ def _bb_cmd_set_default(args, project_path: str) -> None:
|
|
|
5738
5738
|
print(f"[OK] Default repo: {args.project}/{args.repo}")
|
|
5739
5739
|
|
|
5740
5740
|
|
|
5741
|
+
def cmd_creds(args):
|
|
5742
|
+
"""Credential vault management (global + per-project scopes)."""
|
|
5743
|
+
sub = getattr(args, "creds_cmd", None)
|
|
5744
|
+
if not sub:
|
|
5745
|
+
print("Usage: c3 creds {set,get,list,rm,import} [args]")
|
|
5746
|
+
return
|
|
5747
|
+
|
|
5748
|
+
project_path = getattr(args, "project_path", ".") or "."
|
|
5749
|
+
|
|
5750
|
+
if sub == "set":
|
|
5751
|
+
_creds_cmd_set(args, project_path)
|
|
5752
|
+
elif sub == "get":
|
|
5753
|
+
_creds_cmd_get(args, project_path)
|
|
5754
|
+
elif sub == "list":
|
|
5755
|
+
_creds_cmd_list(args, project_path)
|
|
5756
|
+
elif sub == "rm":
|
|
5757
|
+
_creds_cmd_rm(args, project_path)
|
|
5758
|
+
elif sub == "import":
|
|
5759
|
+
_creds_cmd_import(args, project_path)
|
|
5760
|
+
else:
|
|
5761
|
+
print(f"Unknown creds subcommand: {sub}")
|
|
5762
|
+
|
|
5763
|
+
|
|
5764
|
+
def _creds_scope(args) -> str:
|
|
5765
|
+
return "global" if getattr(args, "use_global", False) else "project"
|
|
5766
|
+
|
|
5767
|
+
|
|
5768
|
+
def _creds_entry_line(name: str, entry: dict) -> str:
|
|
5769
|
+
flags = [f for f in ("inject", "agent_readable") if entry.get(f)]
|
|
5770
|
+
parts = [
|
|
5771
|
+
f"{name:<24} {entry.get('scope', '?'):<8} {entry.get('type', 'token'):<10}"
|
|
5772
|
+
f" len={entry.get('value_len', '?')}",
|
|
5773
|
+
]
|
|
5774
|
+
if entry.get("env_var"):
|
|
5775
|
+
parts.append(f"env_var={entry['env_var']}")
|
|
5776
|
+
if flags:
|
|
5777
|
+
parts.append("[" + ",".join(flags) + "]")
|
|
5778
|
+
if entry.get("description"):
|
|
5779
|
+
parts.append(f"-- {entry['description']}")
|
|
5780
|
+
return " ".join(parts)
|
|
5781
|
+
|
|
5782
|
+
|
|
5783
|
+
def _creds_cmd_set(args, project_path: str) -> None:
|
|
5784
|
+
import getpass
|
|
5785
|
+
|
|
5786
|
+
from services import credential_store as cred_store
|
|
5787
|
+
|
|
5788
|
+
value = getattr(args, "value", "") or ""
|
|
5789
|
+
if getattr(args, "stdin", False):
|
|
5790
|
+
value = sys.stdin.read().rstrip("\n")
|
|
5791
|
+
if not value:
|
|
5792
|
+
value = getpass.getpass(f"Value for {args.name}: ")
|
|
5793
|
+
if not value:
|
|
5794
|
+
print("Cancelled -- value required.")
|
|
5795
|
+
return
|
|
5796
|
+
scope = _creds_scope(args)
|
|
5797
|
+
try:
|
|
5798
|
+
entry = cred_store.set_credential(
|
|
5799
|
+
args.name, value,
|
|
5800
|
+
scope=scope, project_path=project_path,
|
|
5801
|
+
description=getattr(args, "desc", "") or "",
|
|
5802
|
+
ctype=getattr(args, "ctype", "token") or "token",
|
|
5803
|
+
env_var=getattr(args, "env_var", "") or "",
|
|
5804
|
+
agent_readable=bool(getattr(args, "agent_readable", False)),
|
|
5805
|
+
inject=bool(getattr(args, "inject", False)),
|
|
5806
|
+
)
|
|
5807
|
+
except (cred_store.CredentialError, RuntimeError) as exc:
|
|
5808
|
+
print(f"[error] {exc}")
|
|
5809
|
+
return
|
|
5810
|
+
print(f"[OK] Stored credential '{args.name}' "
|
|
5811
|
+
f"(scope={scope}, storage={entry['storage']}, len={entry['value_len']})")
|
|
5812
|
+
if entry["agent_readable"]:
|
|
5813
|
+
print("[warn] agent_readable=true -- the agent can read this value "
|
|
5814
|
+
"into its context and transcripts.")
|
|
5815
|
+
|
|
5816
|
+
|
|
5817
|
+
def _creds_cmd_get(args, project_path: str) -> None:
|
|
5818
|
+
from services import credential_store as cred_store
|
|
5819
|
+
|
|
5820
|
+
entry = cred_store.get_entry(args.name, project_path=project_path)
|
|
5821
|
+
if not entry:
|
|
5822
|
+
print(f"[error] no credential named '{args.name}'")
|
|
5823
|
+
return
|
|
5824
|
+
print(_creds_entry_line(args.name, entry))
|
|
5825
|
+
print(f"storage={entry.get('storage', 'keyring')} "
|
|
5826
|
+
f"created={entry.get('created', '?')} updated={entry.get('updated', '?')}")
|
|
5827
|
+
fp = cred_store.fingerprint(args.name, project_path=project_path)
|
|
5828
|
+
print(f"fingerprint={fp or 'unresolvable'}")
|
|
5829
|
+
if getattr(args, "show", False):
|
|
5830
|
+
value = cred_store.get_value(args.name, project_path=project_path)
|
|
5831
|
+
print(value if value is not None else "[error] value missing from store")
|
|
5832
|
+
|
|
5833
|
+
|
|
5834
|
+
def _creds_cmd_list(args, project_path: str) -> None:
|
|
5835
|
+
from services import credential_store as cred_store
|
|
5836
|
+
|
|
5837
|
+
entries = cred_store.list_entries(project_path)
|
|
5838
|
+
if not entries:
|
|
5839
|
+
print("No credentials registered. Use `c3 creds set NAME` "
|
|
5840
|
+
"(add --global for all projects).")
|
|
5841
|
+
return
|
|
5842
|
+
print(f"{len(entries)} credential(s) — project scope shadows global:")
|
|
5843
|
+
for name, entry in entries.items():
|
|
5844
|
+
print(" " + _creds_entry_line(name, entry))
|
|
5845
|
+
|
|
5846
|
+
|
|
5847
|
+
def _creds_cmd_rm(args, project_path: str) -> None:
|
|
5848
|
+
from services import credential_store as cred_store
|
|
5849
|
+
|
|
5850
|
+
scope = _creds_scope(args)
|
|
5851
|
+
entry = cred_store.get_entry(args.name, project_path=project_path)
|
|
5852
|
+
if entry and entry["scope"] == "global" and scope == "project":
|
|
5853
|
+
print(f"[error] '{args.name}' is a global credential -- "
|
|
5854
|
+
"re-run with --global to delete it.")
|
|
5855
|
+
return
|
|
5856
|
+
if cred_store.delete_credential(args.name, scope=scope, project_path=project_path):
|
|
5857
|
+
print(f"[OK] Removed credential '{args.name}' (scope={scope})")
|
|
5858
|
+
else:
|
|
5859
|
+
print(f"[error] no credential named '{args.name}' in {scope} scope")
|
|
5860
|
+
|
|
5861
|
+
|
|
5862
|
+
def _creds_cmd_import(args, project_path: str) -> None:
|
|
5863
|
+
from services import credential_store as cred_store
|
|
5864
|
+
|
|
5865
|
+
env_path = Path(getattr(args, "env_file", ""))
|
|
5866
|
+
if not env_path.exists():
|
|
5867
|
+
print(f"[error] file not found: {env_path}")
|
|
5868
|
+
return
|
|
5869
|
+
try:
|
|
5870
|
+
text = env_path.read_text(encoding="utf-8")
|
|
5871
|
+
result = cred_store.import_env(
|
|
5872
|
+
text, scope=_creds_scope(args), project_path=project_path,
|
|
5873
|
+
overwrite=bool(getattr(args, "overwrite", False)),
|
|
5874
|
+
)
|
|
5875
|
+
except (cred_store.CredentialError, RuntimeError) as exc:
|
|
5876
|
+
print(f"[error] {exc}")
|
|
5877
|
+
return
|
|
5878
|
+
print(f"[OK] Imported {len(result['created'])} credential(s): "
|
|
5879
|
+
f"{', '.join(result['created']) or '-'}")
|
|
5880
|
+
if result["skipped"]:
|
|
5881
|
+
print(f"Skipped {len(result['skipped'])}: {', '.join(result['skipped'])} "
|
|
5882
|
+
"(use --overwrite to replace)")
|
|
5883
|
+
|
|
5884
|
+
|
|
5741
5885
|
def cmd_jira(args):
|
|
5742
5886
|
"""Jira Cloud / Data Center credential + workspace management."""
|
|
5743
5887
|
sub = getattr(args, "jira_cmd", None)
|
|
@@ -7036,6 +7180,7 @@ def main():
|
|
|
7036
7180
|
"hub": cmd_hub,
|
|
7037
7181
|
"bitbucket": cmd_bitbucket,
|
|
7038
7182
|
"jira": cmd_jira,
|
|
7183
|
+
"creds": cmd_creds,
|
|
7039
7184
|
"oracle": cmd_oracle,
|
|
7040
7185
|
"upgrade": cmd_upgrade,
|
|
7041
7186
|
}
|
|
@@ -401,6 +401,48 @@ def build_parser(version: str, parse_cli_ide_arg):
|
|
|
401
401
|
jr_default.add_argument("--name", default="", help="Account name (defaults to the default account)")
|
|
402
402
|
jr_default.add_argument("project_path", nargs="?", default=".")
|
|
403
403
|
|
|
404
|
+
# ── Credential vault (v2.58.0) ──────────────────────────────────────
|
|
405
|
+
p_creds = subparsers.add_parser(
|
|
406
|
+
"creds",
|
|
407
|
+
help="Credential vault — named secrets for agents (global + per-project)",
|
|
408
|
+
)
|
|
409
|
+
creds_subs = p_creds.add_subparsers(dest="creds_cmd")
|
|
410
|
+
|
|
411
|
+
cr_set = creds_subs.add_parser(
|
|
412
|
+
"set", help="Create or update a credential (value via hidden prompt)"
|
|
413
|
+
)
|
|
414
|
+
cr_set.add_argument("name", help="Entry name (env-var safe: [A-Za-z_][A-Za-z0-9_]*)")
|
|
415
|
+
cr_set.add_argument("--value", default="", help="Secret value (prompted via getpass if omitted — preferred)")
|
|
416
|
+
cr_set.add_argument("--stdin", action="store_true", help="Read the value from stdin (piped/multiline values)")
|
|
417
|
+
cr_set.add_argument("--type", dest="ctype", choices=["token", "env", "multiline"], default="token", help="Entry type")
|
|
418
|
+
cr_set.add_argument("--desc", default="", help="Human description shown in list/UI")
|
|
419
|
+
cr_set.add_argument("--env-var", default="", help="Env var name used at injection (default: entry name)")
|
|
420
|
+
cr_set.add_argument("--agent-readable", action="store_true", help="Allow the agent to reveal the decoded value into its context (default: injection-only)")
|
|
421
|
+
cr_set.add_argument("--inject", action="store_true", help="Auto-inject into every c3_shell run")
|
|
422
|
+
cr_set.add_argument("--global", dest="use_global", action="store_true", help="Store in the global scope (~/.c3) so every C3 project can use it")
|
|
423
|
+
# --path (not a trailing positional): a second positional after options
|
|
424
|
+
# breaks argparse on py<3.12 ("unrecognized arguments").
|
|
425
|
+
cr_set.add_argument("--path", dest="project_path", default=".", help="Project directory (default: current)")
|
|
426
|
+
|
|
427
|
+
cr_get = creds_subs.add_parser("get", help="Show entry metadata (masked; --show prints the value)")
|
|
428
|
+
cr_get.add_argument("name")
|
|
429
|
+
cr_get.add_argument("--show", action="store_true", help="Print the decoded value to the terminal")
|
|
430
|
+
cr_get.add_argument("--path", dest="project_path", default=".", help="Project directory (default: current)")
|
|
431
|
+
|
|
432
|
+
cr_list = creds_subs.add_parser("list", help="List credentials visible to this project")
|
|
433
|
+
cr_list.add_argument("--path", dest="project_path", default=".", help="Project directory (default: current)")
|
|
434
|
+
|
|
435
|
+
cr_rm = creds_subs.add_parser("rm", help="Delete a credential (value + registry entry)")
|
|
436
|
+
cr_rm.add_argument("name")
|
|
437
|
+
cr_rm.add_argument("--global", dest="use_global", action="store_true", help="Delete from the global scope")
|
|
438
|
+
cr_rm.add_argument("--path", dest="project_path", default=".", help="Project directory (default: current)")
|
|
439
|
+
|
|
440
|
+
cr_import = creds_subs.add_parser("import", help="Import KEY=VALUE lines from a .env file")
|
|
441
|
+
cr_import.add_argument("env_file", help="Path to the .env file")
|
|
442
|
+
cr_import.add_argument("--global", dest="use_global", action="store_true", help="Import into the global scope")
|
|
443
|
+
cr_import.add_argument("--overwrite", action="store_true", help="Replace entries already registered in the target scope")
|
|
444
|
+
cr_import.add_argument("--path", dest="project_path", default=".", help="Project directory (default: current)")
|
|
445
|
+
|
|
404
446
|
# ── Oracle Discovery API (v2.32.0) ──────────────────────────────────
|
|
405
447
|
p_oracle = subparsers.add_parser(
|
|
406
448
|
"oracle",
|
|
@@ -1773,6 +1773,36 @@ def api_projects_config_get():
|
|
|
1773
1773
|
"defaults": {k: _config_defaults(k) for k in _CONFIG_READ_SECTIONS}})
|
|
1774
1774
|
|
|
1775
1775
|
|
|
1776
|
+
@app.route("/api/projects/credentials", methods=["GET"])
|
|
1777
|
+
def api_projects_credentials():
|
|
1778
|
+
"""Read-only masked credential registry for a project (global entries +
|
|
1779
|
+
project shadows). Values never transit the hub — the explicit field
|
|
1780
|
+
allowlist below returns metadata only; management lives in the project UI
|
|
1781
|
+
(`credentials` is deliberately absent from _CONFIG_WRITE_SECTIONS)."""
|
|
1782
|
+
path = (request.args.get("path") or "").strip()
|
|
1783
|
+
if not path:
|
|
1784
|
+
return jsonify({"error": "path is required"}), 400
|
|
1785
|
+
try:
|
|
1786
|
+
resolved = _resolve_project_path(path)
|
|
1787
|
+
except ValueError as e:
|
|
1788
|
+
return jsonify({"error": str(e)}), 404
|
|
1789
|
+
from services import credential_store as cred_store
|
|
1790
|
+
entries = []
|
|
1791
|
+
for name, entry in cred_store.list_entries(str(resolved)).items():
|
|
1792
|
+
entries.append({
|
|
1793
|
+
"name": name,
|
|
1794
|
+
"scope": entry.get("scope", ""),
|
|
1795
|
+
"type": entry.get("type", "token"),
|
|
1796
|
+
"value_len": entry.get("value_len", 0),
|
|
1797
|
+
"env_var": entry.get("env_var", ""),
|
|
1798
|
+
"inject": bool(entry.get("inject")),
|
|
1799
|
+
"agent_readable": bool(entry.get("agent_readable")),
|
|
1800
|
+
"description": entry.get("description", ""),
|
|
1801
|
+
"updated": entry.get("updated", ""),
|
|
1802
|
+
})
|
|
1803
|
+
return jsonify({"path": str(resolved), "entries": entries})
|
|
1804
|
+
|
|
1805
|
+
|
|
1776
1806
|
@app.route("/api/projects/config", methods=["PUT"])
|
|
1777
1807
|
def api_projects_config_put():
|
|
1778
1808
|
"""Whitelisted section write: deep-merge, atomic replace, audited on the target."""
|
{code_context_control-2.57.1 → code_context_control-2.58.0}/cli/hub_ui/components/drill_panel.js
RENAMED
|
@@ -13,6 +13,7 @@ const DRILL_PANEL_TABS = [
|
|
|
13
13
|
['sessions', 'Sessions'],
|
|
14
14
|
['health', 'Health'],
|
|
15
15
|
['budget', 'Budget'],
|
|
16
|
+
['creds', 'Credentials'],
|
|
16
17
|
['config', 'Config'],
|
|
17
18
|
['mcp', 'MCP'],
|
|
18
19
|
];
|
|
@@ -132,6 +133,7 @@ function DrillPanel({ project, tab, setTab, onClose, onChanged, onOpenModal, pro
|
|
|
132
133
|
case 'sessions': return <DrillSessions project={project} />;
|
|
133
134
|
case 'health': return <DrillHealth project={project} onChanged={onChanged} />;
|
|
134
135
|
case 'budget': return <DrillBudget project={project} />;
|
|
136
|
+
case 'creds': return <DrillCredentials project={project} />;
|
|
135
137
|
case 'config': return <ConfigEditor project={project} />;
|
|
136
138
|
case 'mcp': return <McpManager project={project} onChanged={onChanged} />;
|
|
137
139
|
default: return <DrillOverview project={project} onChanged={onChanged} setTab={setTab} />;
|
{code_context_control-2.57.1 → code_context_control-2.58.0}/cli/hub_ui/components/drill_views.js
RENAMED
|
@@ -283,6 +283,56 @@ function DrillLedger({ project }) {
|
|
|
283
283
|
}
|
|
284
284
|
|
|
285
285
|
// ── Sessions ───────────────────────────────────────────────────
|
|
286
|
+
// Read-only: the hub never transits credential values — this lists metadata
|
|
287
|
+
// from GET /api/projects/credentials; management lives in the project UI.
|
|
288
|
+
function DrillCredentials({ project }) {
|
|
289
|
+
const [data, setData] = useState(null);
|
|
290
|
+
const [err, setErr] = useState(null);
|
|
291
|
+
|
|
292
|
+
const load = async () => {
|
|
293
|
+
setErr(null);
|
|
294
|
+
try {
|
|
295
|
+
const d = await api.get('/api/projects/credentials?path=' + encodeURIComponent(project.path));
|
|
296
|
+
setData(d);
|
|
297
|
+
} catch (e) { setErr(e.message); }
|
|
298
|
+
};
|
|
299
|
+
useEffect(() => { setData(null); load(); }, [project.path]);
|
|
300
|
+
|
|
301
|
+
if (err) return <DrillMsg text={'Failed to load credentials: ' + err} color={T.error} />;
|
|
302
|
+
if (!data) return <DrillMsg text="Loading credentials…" />;
|
|
303
|
+
|
|
304
|
+
const entries = data.entries || [];
|
|
305
|
+
return (
|
|
306
|
+
<div className="fade-up">
|
|
307
|
+
<div style={{ fontSize: 11, color: T.textMuted, lineHeight: 1.5, marginBottom: 12 }}>
|
|
308
|
+
Read-only view — values never transit the hub. Manage entries (and the
|
|
309
|
+
agent_readable / inject flags) in this project's own UI Credentials tab
|
|
310
|
+
or via <span className="mono">c3 creds</span>.
|
|
311
|
+
</div>
|
|
312
|
+
{entries.length === 0 ? (
|
|
313
|
+
<DrillMsg text="No credentials registered for this project." />
|
|
314
|
+
) : entries.map((entry) => (
|
|
315
|
+
<div key={entry.scope + '|' + entry.name} style={{
|
|
316
|
+
display: 'flex', alignItems: 'center', gap: 8, padding: '8px 0',
|
|
317
|
+
borderBottom: `1px solid ${T.border}`, fontSize: 12,
|
|
318
|
+
}}>
|
|
319
|
+
<I name="lock" size={12} color={T.textMuted} />
|
|
320
|
+
<span className="mono" style={{ fontWeight: 600, color: T.text }}>{entry.name}</span>
|
|
321
|
+
<Badge color={entry.scope === 'global' ? T.accent : T.ok}>{entry.scope}</Badge>
|
|
322
|
+
<Badge color={T.textMuted}>{entry.type}</Badge>
|
|
323
|
+
<span className="mono" style={{ color: T.textDim }}>len={entry.value_len}</span>
|
|
324
|
+
{!!entry.inject && <Badge color={T.warn}>inject</Badge>}
|
|
325
|
+
{!!entry.agent_readable && <Badge color={T.error}>agent_readable</Badge>}
|
|
326
|
+
<span style={{
|
|
327
|
+
flex: 1, color: T.textMuted, fontSize: 11, textAlign: 'right',
|
|
328
|
+
whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis',
|
|
329
|
+
}}>{entry.description}</span>
|
|
330
|
+
</div>
|
|
331
|
+
))}
|
|
332
|
+
</div>
|
|
333
|
+
);
|
|
334
|
+
}
|
|
335
|
+
|
|
286
336
|
function DrillSessions({ project }) {
|
|
287
337
|
const [data, setData] = useState(null);
|
|
288
338
|
const [needsInit, setNeedsInit] = useState(false);
|
|
@@ -355,6 +355,22 @@ def _finalize_response(ctx: Context, tool_name: str, args: dict,
|
|
|
355
355
|
snap_pct = 0
|
|
356
356
|
svc = _svc(ctx)
|
|
357
357
|
|
|
358
|
+
# Credential hygiene: scrub any decoded vault value from every PERSISTED
|
|
359
|
+
# copy (session store, activity log, auto-memory). The response returned
|
|
360
|
+
# to the model is deliberately untouched — reveal is gated upstream by
|
|
361
|
+
# the per-entry agent_readable flag, and injected values only appear in
|
|
362
|
+
# output when a subprocess echoed them (already scrubbed in c3_shell;
|
|
363
|
+
# this is the belt-and-braces layer for every other tool).
|
|
364
|
+
persisted_response = response
|
|
365
|
+
try:
|
|
366
|
+
from services import credential_store as _creds
|
|
367
|
+
if _creds._ACTIVE_SECRETS:
|
|
368
|
+
args = _creds.redact_obj(args)
|
|
369
|
+
summary = _creds.redact_text(summary)
|
|
370
|
+
persisted_response = _creds.redact_text(response)
|
|
371
|
+
except Exception:
|
|
372
|
+
pass
|
|
373
|
+
|
|
358
374
|
# Minimal critical section: only the module-global timing state needs
|
|
359
375
|
# exclusive access. Disk I/O happens outside the lock so concurrent tool
|
|
360
376
|
# calls don't serialize on append-only JSONL writes.
|
|
@@ -380,7 +396,7 @@ def _finalize_response(ctx: Context, tool_name: str, args: dict,
|
|
|
380
396
|
tracker.ping("tool") # throttled heartbeat; idle gaps close sessions
|
|
381
397
|
except Exception:
|
|
382
398
|
pass
|
|
383
|
-
svc.session_mgr.track_response(tool_name,
|
|
399
|
+
svc.session_mgr.track_response(tool_name, persisted_response, response_tokens=response_tokens)
|
|
384
400
|
|
|
385
401
|
hybrid_cfg = svc.hybrid_config or {}
|
|
386
402
|
|
|
@@ -399,7 +415,7 @@ def _finalize_response(ctx: Context, tool_name: str, args: dict,
|
|
|
399
415
|
# --- Outside lock: auto-memory extraction (may do file I/O / Ollama) ---
|
|
400
416
|
if hasattr(svc, "auto_memory"):
|
|
401
417
|
try:
|
|
402
|
-
svc.auto_memory.on_tool_complete(tool_name, args, summary,
|
|
418
|
+
svc.auto_memory.on_tool_complete(tool_name, args, summary, persisted_response)
|
|
403
419
|
except Exception:
|
|
404
420
|
pass
|
|
405
421
|
|
|
@@ -422,7 +438,7 @@ def _finalize_response(ctx: Context, tool_name: str, args: dict,
|
|
|
422
438
|
return response
|
|
423
439
|
|
|
424
440
|
|
|
425
|
-
# ─── TOOL REGISTRATIONS (
|
|
441
|
+
# ─── TOOL REGISTRATIONS (19 tools) ────────────────────────────────
|
|
426
442
|
# Each tool's first docstring line should state WHEN to reach for it —
|
|
427
443
|
# that's what Claude reads when selecting between tools.
|
|
428
444
|
|
|
@@ -711,10 +727,14 @@ async def c3_impact(target: str, file_path: str = "", mode: str = "symbol",
|
|
|
711
727
|
@mcp.tool()
|
|
712
728
|
async def c3_shell(cmd: str, cwd: str = "", timeout: int = 60,
|
|
713
729
|
filter_output: bool = True, log: bool = True,
|
|
730
|
+
env_creds: str = "",
|
|
714
731
|
ctx: Context = None) -> str:
|
|
715
732
|
"""EXECUTE shell command — structured returns, auto-filter, ledger-aware.
|
|
716
733
|
Use for tests, git, build, scripts. Returns exit_code/stdout/stderr/duration_ms.
|
|
717
734
|
Auto-filters stdout >30 lines; auto-logs git mutations to the edit ledger.
|
|
735
|
+
Credentials: env_creds='NAME1,NAME2' injects vault entries as env vars, and
|
|
736
|
+
{{cred:NAME}} inside cmd expands server-side — decoded values never enter
|
|
737
|
+
model context (see c3_credentials; echoed values are auto-redacted).
|
|
718
738
|
Best-effort block of catastrophic commands (rm -rf of /, a top-level system dir, or
|
|
719
739
|
$HOME/~; fork bombs; whole-drive wipes) — a guard, NOT a sandbox. Soft-warns on
|
|
720
740
|
--force, --no-verify, reset --hard.
|
|
@@ -725,7 +745,8 @@ async def c3_shell(cmd: str, cwd: str = "", timeout: int = 60,
|
|
|
725
745
|
def finalize(name, args, resp, summ, **kw):
|
|
726
746
|
return _finalize_response(ctx, name, args, resp, summ, **kw)
|
|
727
747
|
|
|
728
|
-
return await handle_shell(cmd, cwd, timeout, filter_output, log, svc, finalize
|
|
748
|
+
return await handle_shell(cmd, cwd, timeout, filter_output, log, svc, finalize,
|
|
749
|
+
env_creds=env_creds)
|
|
729
750
|
|
|
730
751
|
|
|
731
752
|
@mcp.tool()
|
|
@@ -822,6 +843,40 @@ async def c3_jira(
|
|
|
822
843
|
)
|
|
823
844
|
|
|
824
845
|
|
|
846
|
+
@mcp.tool()
|
|
847
|
+
async def c3_credentials(
|
|
848
|
+
action: str,
|
|
849
|
+
name: str = "",
|
|
850
|
+
value: str = "",
|
|
851
|
+
scope: str = "",
|
|
852
|
+
description: str = "",
|
|
853
|
+
ctype: str = "",
|
|
854
|
+
env_var: str = "",
|
|
855
|
+
inject: bool = False,
|
|
856
|
+
agent_readable: bool = False,
|
|
857
|
+
ctx: Context = None,
|
|
858
|
+
) -> str:
|
|
859
|
+
"""CREDENTIAL VAULT — named secrets the user manages (global + per-project), injection-first.
|
|
860
|
+
actions: list, describe (name), check (name), reveal (name — only entries the
|
|
861
|
+
user marked agent_readable), set (name, value [scope=project|global] [ctype=token|env|multiline]
|
|
862
|
+
[description] [env_var] [inject]), delete (name [scope]).
|
|
863
|
+
To USE a credential, do NOT reveal it — pass env_creds='NAME1,NAME2' to c3_shell
|
|
864
|
+
(injected as env vars) or write {{cred:NAME}} inside the cmd (expanded server-side);
|
|
865
|
+
the decoded value never enters model context. Values live in the OS keyring /
|
|
866
|
+
an encrypted sidecar, never in config files. Mutations and reveals are ledger-logged."""
|
|
867
|
+
svc = _svc(ctx)
|
|
868
|
+
|
|
869
|
+
def finalize(fname, fargs, fresp, fsumm, **kw):
|
|
870
|
+
return _finalize_response(ctx, fname, fargs, fresp, fsumm, **kw)
|
|
871
|
+
|
|
872
|
+
from cli.tools.credentials import handle_credentials
|
|
873
|
+
return await asyncio.to_thread(
|
|
874
|
+
handle_credentials, action, svc, finalize,
|
|
875
|
+
name=name, value=value, scope=scope, description=description,
|
|
876
|
+
ctype=ctype, env_var=env_var, inject=inject, agent_readable=agent_readable,
|
|
877
|
+
)
|
|
878
|
+
|
|
879
|
+
|
|
825
880
|
@mcp.tool()
|
|
826
881
|
async def c3_project(
|
|
827
882
|
action: str,
|