code-context-control 2.86.0__tar.gz → 2.89.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.86.0/code_context_control.egg-info → code_context_control-2.89.0}/PKG-INFO +1 -1
- {code_context_control-2.86.0 → code_context_control-2.89.0}/cli/c3.py +128 -9
- {code_context_control-2.86.0 → code_context_control-2.89.0}/cli/commands/parser.py +15 -2
- {code_context_control-2.86.0 → code_context_control-2.89.0}/cli/guide/bitbucket.html +12 -3
- {code_context_control-2.86.0 → code_context_control-2.89.0}/cli/guide/credentials.html +80 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/cli/guide/tools.html +33 -6
- {code_context_control-2.86.0 → code_context_control-2.89.0}/cli/hook_pretool_enforce.py +2 -1
- {code_context_control-2.86.0 → code_context_control-2.89.0}/cli/hub_server.py +33 -2
- {code_context_control-2.86.0 → code_context_control-2.89.0}/cli/hub_ui/components/drill_panel.js +2 -2
- {code_context_control-2.86.0 → code_context_control-2.89.0}/cli/hub_ui/components/hub_credentials.js +227 -23
- {code_context_control-2.86.0 → code_context_control-2.89.0}/cli/mcp_server.py +72 -15
- {code_context_control-2.86.0 → code_context_control-2.89.0}/cli/server.py +34 -10
- {code_context_control-2.86.0 → code_context_control-2.89.0}/cli/tools/bitbucket.py +190 -6
- {code_context_control-2.86.0 → code_context_control-2.89.0}/cli/tools/credentials.py +105 -4
- {code_context_control-2.86.0 → code_context_control-2.89.0}/cli/tools/jira.py +299 -10
- {code_context_control-2.86.0 → code_context_control-2.89.0}/cli/tools/shell.py +52 -8
- {code_context_control-2.86.0 → code_context_control-2.89.0}/cli/ui/components/credentials.js +251 -23
- {code_context_control-2.86.0 → code_context_control-2.89.0/code_context_control.egg-info}/PKG-INFO +1 -1
- {code_context_control-2.86.0 → code_context_control-2.89.0}/code_context_control.egg-info/SOURCES.txt +2 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/oracle/oracle_server.py +4 -4
- {code_context_control-2.86.0 → code_context_control-2.89.0}/oracle/services/local_session.py +28 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/oracle/services/mobile_api.py +29 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/pyproject.toml +1 -1
- {code_context_control-2.86.0 → code_context_control-2.89.0}/services/bitbucket_client.py +127 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/services/claude_md.py +2 -2
- code_context_control-2.89.0/services/cred_telemetry.py +303 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/services/credential_store.py +399 -23
- {code_context_control-2.86.0 → code_context_control-2.89.0}/services/jira_client.py +174 -3
- {code_context_control-2.86.0 → code_context_control-2.89.0}/services/jira_cloud.py +126 -2
- {code_context_control-2.86.0 → code_context_control-2.89.0}/services/jira_data_center.py +180 -4
- {code_context_control-2.86.0 → code_context_control-2.89.0}/services/parser.py +24 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tests/test_bitbucket_client.py +141 -0
- code_context_control-2.89.0/tests/test_bitbucket_tool.py +364 -0
- code_context_control-2.89.0/tests/test_cred_telemetry.py +189 -0
- code_context_control-2.89.0/tests/test_credential_store.py +525 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tests/test_credentials_routes.py +82 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tests/test_credentials_tool.py +96 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tests/test_delegate_cascade.py +52 -1
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tests/test_hub_credentials_routes_write.py +54 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tests/test_jira_client.py +295 -1
- code_context_control-2.89.0/tests/test_jira_tool.py +598 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tests/test_mobile_security_api.py +32 -1
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tests/test_oracle_session_bootstrap.py +101 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tests/test_shell_creds.py +85 -2
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tests/test_validate.py +57 -0
- code_context_control-2.86.0/tests/test_bitbucket_tool.py +0 -189
- code_context_control-2.86.0/tests/test_credential_store.py +0 -270
- code_context_control-2.86.0/tests/test_jira_tool.py +0 -293
- {code_context_control-2.86.0 → code_context_control-2.89.0}/LICENSE +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/README.md +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/cli/__init__.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/cli/_hook_utils.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/cli/commands/__init__.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/cli/commands/common.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/cli/docs.html +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/cli/edits.html +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/cli/guide/access.html +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/cli/guide/getting-started.html +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/cli/guide/index.html +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/cli/guide/masking.html +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/cli/guide/oracle.html +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/cli/guide/shared.css +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/cli/guide/workflow.html +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/cli/hook_access_guard.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/cli/hook_artifact.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/cli/hook_auto_snapshot.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/cli/hook_c3_signal.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/cli/hook_c3read.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/cli/hook_dispatch.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/cli/hook_edit_ledger.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/cli/hook_edit_unlock.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/cli/hook_filter.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/cli/hook_ghost_files.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/cli/hook_prompt_recall.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/cli/hook_read.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/cli/hook_session_stats.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/cli/hook_terse_advisor.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/cli/hub_ui/app.js +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/cli/hub_ui/components/add_project.js +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/cli/hub_ui/components/config_editor.js +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/cli/hub_ui/components/drill_artifacts.js +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/cli/hub_ui/components/drill_health.js +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/cli/hub_ui/components/drill_subprojects.js +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/cli/hub_ui/components/drill_tasks.js +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/cli/hub_ui/components/drill_views.js +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/cli/hub_ui/components/global_search.js +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/cli/hub_ui/components/hub_ci.js +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/cli/hub_ui/components/hub_enforcement.js +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/cli/hub_ui/components/hub_locks.js +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/cli/hub_ui/components/mcp_manager.js +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/cli/hub_ui/components/modals.js +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/cli/hub_ui/components/project_card.js +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/cli/hub_ui/components/project_tree.js +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/cli/hub_ui/components/session_drawer.js +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/cli/hub_ui/components/settings_modal.js +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/cli/hub_ui/components/sidebar.js +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/cli/hub_ui/components/summary_bar.js +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/cli/hub_ui/components/task_board.js +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/cli/hub_ui/components/toasts.js +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/cli/hub_ui/components/topbar.js +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/cli/hub_ui/state.js +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/cli/hub_ui.html +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/cli/mcp_proxy.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/cli/progress.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/cli/tools/__init__.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/cli/tools/_grants.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/cli/tools/_helpers.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/cli/tools/agent.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/cli/tools/artifacts.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/cli/tools/ci.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/cli/tools/compress.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/cli/tools/delegate.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/cli/tools/edit.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/cli/tools/edit_verify.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/cli/tools/edits.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/cli/tools/federate.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/cli/tools/filter.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/cli/tools/impact.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/cli/tools/locks.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/cli/tools/memory.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/cli/tools/override.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/cli/tools/project.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/cli/tools/read.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/cli/tools/search.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/cli/tools/session.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/cli/tools/status.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/cli/tools/tasks.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/cli/tools/validate.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/cli/ui/api.js +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/cli/ui/app.js +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/cli/ui/components/access.js +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/cli/ui/components/bitbucket.js +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/cli/ui/components/chat.js +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/cli/ui/components/dashboard.js +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/cli/ui/components/edits.js +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/cli/ui/components/enforcement.js +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/cli/ui/components/instructions.js +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/cli/ui/components/jira.js +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/cli/ui/components/memory.js +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/cli/ui/components/sessions.js +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/cli/ui/components/settings.js +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/cli/ui/components/sidebar.js +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/cli/ui/components/tasks.js +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/cli/ui/icons.js +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/cli/ui/pm_shared.js +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/cli/ui/shared.js +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/cli/ui/theme.js +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/cli/ui.html +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/cli/ui_legacy.html +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/cli/ui_nano.html +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/code_context_control.egg-info/dependency_links.txt +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/code_context_control.egg-info/entry_points.txt +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/code_context_control.egg-info/requires.txt +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/code_context_control.egg-info/top_level.txt +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/core/__init__.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/core/config.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/core/ide.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/core/mcp_toml.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/core/web_security.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/oracle/__init__.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/oracle/config.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/oracle/mcp_oracle.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/oracle/oracle_ui.html +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/oracle/services/__init__.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/oracle/services/activity_reporter.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/oracle/services/api_auth.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/oracle/services/c3_bridge.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/oracle/services/chat_engine.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/oracle/services/chat_poll.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/oracle/services/chat_store.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/oracle/services/cross_memory.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/oracle/services/discovery_audit.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/oracle/services/federated_graph.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/oracle/services/health_checker.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/oracle/services/insight_engine.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/oracle/services/memory_reader.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/oracle/services/memory_writer.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/oracle/services/project_scanner.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/oracle/services/review_agent.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/oracle/services/tool_executor.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/oracle/services/tool_registry.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/oracle/ui/activity.js +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/oracle/ui/agents.js +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/oracle/ui/app.js +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/oracle/ui/busy.js +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/oracle/ui/chat/conversations.js +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/oracle/ui/chat/input.js +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/oracle/ui/chat/markdown.js +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/oracle/ui/chat/send.js +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/oracle/ui/chat/stream_renderer.js +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/oracle/ui/chat/toolbar.js +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/oracle/ui/core.js +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/oracle/ui/crossgraph.js +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/oracle/ui/header.js +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/oracle/ui/insights.js +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/oracle/ui/projects.js +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/oracle/ui/qrcode.js +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/oracle/ui/settings.js +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/oracle/ui/suggestions.js +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/oracle/ui/theme_tabs.js +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/services/__init__.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/services/access_guard.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/services/access_telemetry.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/services/activity_log.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/services/agent_base.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/services/agent_locks.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/services/agents.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/services/artifact_defs.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/services/artifact_store.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/services/auto_memory.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/services/bench/__init__.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/services/bench/external/__init__.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/services/bench/external/aider_polyglot.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/services/bench/external/swe_bench.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/services/benchmark_dashboard.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/services/bitbucket_credentials.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/services/ci_act.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/services/ci_cache.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/services/ci_expr.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/services/ci_failures.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/services/ci_github.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/services/ci_impact.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/services/ci_intel.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/services/ci_runner.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/services/ci_workflow.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/services/circuit_breaker.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/services/compressor.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/services/context_snapshot.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/services/conversation_store.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/services/doc_index.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/services/e2e_benchmark.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/services/e2e_evaluator.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/services/e2e_tasks.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/services/edit_ledger.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/services/embedding_index.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/services/enforcement_policy.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/services/error_reporting.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/services/file_memory.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/services/git_context.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/services/hub_service.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/services/indexer.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/services/jira_credentials.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/services/jira_links.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/services/mask_activation.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/services/mask_mirror.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/services/mask_presets.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/services/memory.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/services/memory_consolidator.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/services/memory_distiller.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/services/memory_graph.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/services/memory_grounder.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/services/memory_queue.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/services/memory_scorer.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/services/metrics.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/services/notifications.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/services/ollama_bridge.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/services/ollama_client.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/services/ollama_credentials.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/services/output_filter.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/services/override_grants.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/services/override_policy.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/services/override_requests.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/services/override_wake.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/services/project_manager.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/services/project_runtime.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/services/protocol.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/services/proxy_state.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/services/repo_map.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/services/retention.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/services/retrieval_broker.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/services/router.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/services/runtime.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/services/scanner.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/services/session_benchmark.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/services/session_manager.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/services/session_preloader.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/services/subprojects.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/services/task_store.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/services/telemetry.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/services/text_index.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/services/time_tracker.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/services/tool_classifier.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/services/transcript_index.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/services/validation_cache.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/services/vector_store.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/services/watcher.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/services/win_subprocess.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/setup.cfg +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tests/test_access_builtin_optout.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tests/test_access_guard.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tests/test_access_guard_meta.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tests/test_access_guard_shell_project.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tests/test_access_guard_surfaces.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tests/test_access_guard_wiring.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tests/test_activity_reporter.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tests/test_agent_locks.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tests/test_aider_polyglot.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tests/test_antigravity_transition.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tests/test_artifact_store.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tests/test_artifact_tool.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tests/test_bitbucket_cli_smoke.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tests/test_bitbucket_config_fallback.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tests/test_bitbucket_credentials.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tests/test_c3_bridge_project_artifacts.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tests/test_c3_shell.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tests/test_chat_poll.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tests/test_ci_act.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tests/test_ci_cache.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tests/test_ci_expr.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tests/test_ci_impact.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tests/test_ci_intel.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tests/test_ci_runner.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tests/test_ci_workflow.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tests/test_circuit_breaker.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tests/test_claude_md_merge.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tests/test_cli_smoke.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tests/test_compressor_large_file.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tests/test_creds_cli_smoke.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tests/test_delegate_version_probe.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tests/test_e2e_benchmark.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tests/test_edit_ledger_deadline.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tests/test_edit_ledger_hook.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tests/test_edit_locking.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tests/test_edit_normalization.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tests/test_edit_verify.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tests/test_embedding_index_deadlock.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tests/test_enforcement_flip.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tests/test_enforcement_policy.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tests/test_enforcement_routes.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tests/test_federated_graph.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tests/test_filter_backoff.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tests/test_ghost_files.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tests/test_ghost_generation.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tests/test_git_branch_awareness.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tests/test_hook_access_guard.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tests/test_hook_codex_compat.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tests/test_hook_dispatch.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tests/test_hook_pretool_enforce.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tests/test_hook_prompt_recall.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tests/test_hook_smoke.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tests/test_hook_state.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tests/test_hook_utf8_stdio.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tests/test_hub_credentials_route.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tests/test_hub_enforcement_routes.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tests/test_hub_inspect_api.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tests/test_hub_locks_routes.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tests/test_hub_server_smoke.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tests/test_hub_subproject_links.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tests/test_ide_workflow_adaptation.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tests/test_init_scan.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tests/test_install_mcp_entrypoint.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tests/test_jira_cli_smoke.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tests/test_jira_config_fallback.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tests/test_jira_credentials.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tests/test_jira_links.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tests/test_jira_routes.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tests/test_lazy_store_init.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tests/test_mask_guard.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tests/test_mask_routes.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tests/test_mask_surfaces.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tests/test_mcp_host_guard.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tests/test_mcp_memory_timeout.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tests/test_mcp_server_smoke.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tests/test_mcp_toml.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tests/test_memory_distiller.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tests/test_memory_graph_api.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tests/test_memory_queue.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tests/test_memory_system.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tests/test_mobile_api.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tests/test_mobile_extras.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tests/test_mobile_override_routes.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tests/test_no_stale_model_pins.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tests/test_notification_dedup.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tests/test_notification_discipline.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tests/test_ollama_credentials.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tests/test_oracle_api_auth.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tests/test_oracle_apikey_api.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tests/test_oracle_c3_bridge.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tests/test_oracle_chat_engine.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tests/test_oracle_chat_store.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tests/test_oracle_discovery_api.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tests/test_oracle_discovery_audit.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tests/test_oracle_local_auth.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tests/test_oracle_ollama_bridge.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tests/test_oracle_scanner_cache.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tests/test_oracle_security_fixes.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tests/test_oracle_subproject_awareness.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tests/test_oracle_ui_bundle.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tests/test_output_filter.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tests/test_override_grants.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tests/test_override_grants_mcp.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tests/test_override_requests.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tests/test_override_wake.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tests/test_permissions.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tests/test_pm_api.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tests/test_project_manager.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tests/test_project_manager_merge.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tests/test_project_tool.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tests/test_read_coercion.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tests/test_read_edit_parity.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tests/test_related_facts.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tests/test_repo_map.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tests/test_response_boilerplate.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tests/test_retention.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tests/test_review_digest.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tests/test_service_durability.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tests/test_session_benchmark.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tests/test_session_budget.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tests/test_shell_robustness.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tests/test_subproject_exclusion.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tests/test_subproject_federation.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tests/test_subprojects.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tests/test_swe_bench.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tests/test_task_store.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tests/test_task_tool.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tests/test_time_tracker.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tests/test_token_telemetry.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tests/test_tool_registry.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tests/test_upgrade_and_version.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tests/test_vault_write_guard.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tests/test_version_sync.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tests/test_web_security.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tests/test_windows_reliability.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tui/__init__.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tui/backend.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tui/main.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tui/screens/__init__.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tui/screens/benchmark_view.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tui/screens/claudemd_view.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tui/screens/compress_view.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tui/screens/index_view.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tui/screens/init_view.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tui/screens/mcp_view.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tui/screens/optimize_view.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tui/screens/pipe_view.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tui/screens/projects_view.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tui/screens/search_view.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tui/screens/session_view.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tui/screens/stats.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tui/screens/ui_view.py +0 -0
- {code_context_control-2.86.0 → code_context_control-2.89.0}/tui/theme.tcss +0 -0
{code_context_control-2.86.0/code_context_control.egg-info → code_context_control-2.89.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.89.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
|
|
@@ -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.89.0"
|
|
96
96
|
|
|
97
97
|
|
|
98
98
|
def _compress_file_cli(compressor, path, mode="smart", **kw):
|
|
@@ -5899,7 +5899,7 @@ def cmd_creds(args):
|
|
|
5899
5899
|
"""Credential vault management (global + per-project scopes)."""
|
|
5900
5900
|
sub = getattr(args, "creds_cmd", None)
|
|
5901
5901
|
if not sub:
|
|
5902
|
-
print("Usage: c3 creds {set,get,list,rm,import} [args]")
|
|
5902
|
+
print("Usage: c3 creds {set,get,list,rm,import,usage} [args]")
|
|
5903
5903
|
return
|
|
5904
5904
|
|
|
5905
5905
|
project_path = getattr(args, "project_path", ".") or "."
|
|
@@ -5914,6 +5914,8 @@ def cmd_creds(args):
|
|
|
5914
5914
|
_creds_cmd_rm(args, project_path)
|
|
5915
5915
|
elif sub == "import":
|
|
5916
5916
|
_creds_cmd_import(args, project_path)
|
|
5917
|
+
elif sub == "usage":
|
|
5918
|
+
_creds_cmd_usage(args, project_path)
|
|
5917
5919
|
else:
|
|
5918
5920
|
print(f"Unknown creds subcommand: {sub}")
|
|
5919
5921
|
|
|
@@ -5928,6 +5930,9 @@ def _creds_entry_line(name: str, entry: dict) -> str:
|
|
|
5928
5930
|
f"{name:<24} {entry.get('scope', '?'):<8} {entry.get('type', 'token'):<10}"
|
|
5929
5931
|
f" len={entry.get('value_len', '?')}",
|
|
5930
5932
|
]
|
|
5933
|
+
display = entry.get("display") or {}
|
|
5934
|
+
if display:
|
|
5935
|
+
parts.append(" ".join(str(v) for v in display.values() if v))
|
|
5931
5936
|
if entry.get("env_var"):
|
|
5932
5937
|
parts.append(f"env_var={entry['env_var']}")
|
|
5933
5938
|
if flags:
|
|
@@ -5937,16 +5942,49 @@ def _creds_entry_line(name: str, entry: dict) -> str:
|
|
|
5937
5942
|
return " ".join(parts)
|
|
5938
5943
|
|
|
5939
5944
|
|
|
5945
|
+
_CREDS_HIDDEN_FIELDS = {"number", "cvc", "ssn"} # prompted via getpass
|
|
5946
|
+
|
|
5947
|
+
|
|
5948
|
+
def _creds_prompt_structured(name: str, ctype: str) -> str:
|
|
5949
|
+
"""Interactive per-field prompt for a structured entry; returns JSON.
|
|
5950
|
+
Sensitive fields use a hidden prompt; empty optional fields are skipped."""
|
|
5951
|
+
import getpass
|
|
5952
|
+
import json as _json
|
|
5953
|
+
|
|
5954
|
+
from services import credential_store as cred_store
|
|
5955
|
+
|
|
5956
|
+
required, optional = cred_store.schema_fields(ctype)
|
|
5957
|
+
print(f"Enter {ctype} fields for '{name}' "
|
|
5958
|
+
"(optional fields: press Enter to skip):")
|
|
5959
|
+
fields: dict = {}
|
|
5960
|
+
for fname in list(required) + list(optional):
|
|
5961
|
+
tag = "" if fname in required else " (optional)"
|
|
5962
|
+
if fname in _CREDS_HIDDEN_FIELDS:
|
|
5963
|
+
raw = getpass.getpass(f" {fname}{tag}: ")
|
|
5964
|
+
else:
|
|
5965
|
+
raw = input(f" {fname}{tag}: ")
|
|
5966
|
+
if raw.strip():
|
|
5967
|
+
fields[fname] = raw.strip()
|
|
5968
|
+
return _json.dumps(fields)
|
|
5969
|
+
|
|
5970
|
+
|
|
5940
5971
|
def _creds_cmd_set(args, project_path: str) -> None:
|
|
5941
5972
|
import getpass
|
|
5942
5973
|
|
|
5943
5974
|
from services import credential_store as cred_store
|
|
5944
5975
|
|
|
5976
|
+
ctype = getattr(args, "ctype", "token") or "token"
|
|
5945
5977
|
value = getattr(args, "value", "") or ""
|
|
5946
5978
|
if getattr(args, "stdin", False):
|
|
5947
5979
|
value = sys.stdin.read().rstrip("\n")
|
|
5948
5980
|
if not value:
|
|
5949
|
-
|
|
5981
|
+
if ctype in cred_store.STRUCTURED_TYPES:
|
|
5982
|
+
value = _creds_prompt_structured(args.name, ctype)
|
|
5983
|
+
if value == "{}":
|
|
5984
|
+
print("Cancelled -- no fields entered.")
|
|
5985
|
+
return
|
|
5986
|
+
else:
|
|
5987
|
+
value = getpass.getpass(f"Value for {args.name}: ")
|
|
5950
5988
|
if not value:
|
|
5951
5989
|
print("Cancelled -- value required.")
|
|
5952
5990
|
return
|
|
@@ -5956,7 +5994,7 @@ def _creds_cmd_set(args, project_path: str) -> None:
|
|
|
5956
5994
|
args.name, value,
|
|
5957
5995
|
scope=scope, project_path=project_path,
|
|
5958
5996
|
description=getattr(args, "desc", "") or "",
|
|
5959
|
-
ctype=
|
|
5997
|
+
ctype=ctype,
|
|
5960
5998
|
env_var=getattr(args, "env_var", "") or "",
|
|
5961
5999
|
agent_readable=bool(getattr(args, "agent_readable", False)),
|
|
5962
6000
|
inject=bool(getattr(args, "inject", False)),
|
|
@@ -5971,6 +6009,19 @@ def _creds_cmd_set(args, project_path: str) -> None:
|
|
|
5971
6009
|
"into its context and transcripts.")
|
|
5972
6010
|
|
|
5973
6011
|
|
|
6012
|
+
def _creds_count_show(refs, project_path: str) -> None:
|
|
6013
|
+
"""Count a terminal --show like any other use: state counter + history."""
|
|
6014
|
+
from services import credential_store as cred_store
|
|
6015
|
+
try:
|
|
6016
|
+
cred_store.touch_last_used(
|
|
6017
|
+
sorted({str(r).partition(".")[0] for r in refs}), project_path)
|
|
6018
|
+
from services import cred_telemetry as ct
|
|
6019
|
+
ct.record_use(refs, project_path=project_path,
|
|
6020
|
+
action=ct.ACTION_CLI_SHOW, surface="cli")
|
|
6021
|
+
except Exception:
|
|
6022
|
+
pass
|
|
6023
|
+
|
|
6024
|
+
|
|
5974
6025
|
def _creds_cmd_get(args, project_path: str) -> None:
|
|
5975
6026
|
from services import credential_store as cred_store
|
|
5976
6027
|
|
|
@@ -5981,11 +6032,46 @@ def _creds_cmd_get(args, project_path: str) -> None:
|
|
|
5981
6032
|
print(_creds_entry_line(args.name, entry))
|
|
5982
6033
|
print(f"storage={entry.get('storage', 'keyring')} "
|
|
5983
6034
|
f"created={entry.get('created', '?')} updated={entry.get('updated', '?')}")
|
|
5984
|
-
|
|
5985
|
-
|
|
5986
|
-
if
|
|
5987
|
-
|
|
5988
|
-
print(
|
|
6035
|
+
stype = cred_store.structured_type(args.name, project_path=project_path)
|
|
6036
|
+
field = (getattr(args, "field", "") or "").strip()
|
|
6037
|
+
if not stype:
|
|
6038
|
+
fp = cred_store.fingerprint(args.name, project_path=project_path)
|
|
6039
|
+
print(f"fingerprint={fp or 'unresolvable'}")
|
|
6040
|
+
if field:
|
|
6041
|
+
print(f"[error] '{args.name}' is not structured -- --field does not apply")
|
|
6042
|
+
return
|
|
6043
|
+
if getattr(args, "show", False):
|
|
6044
|
+
value = cred_store.get_value(args.name, project_path=project_path)
|
|
6045
|
+
print(value if value is not None
|
|
6046
|
+
else "[error] value missing from store")
|
|
6047
|
+
if value is not None:
|
|
6048
|
+
_creds_count_show([args.name], project_path)
|
|
6049
|
+
return
|
|
6050
|
+
print(f"fields: {', '.join(entry.get('fields') or []) or 'none recorded'}")
|
|
6051
|
+
if not getattr(args, "show", False):
|
|
6052
|
+
if field:
|
|
6053
|
+
print("[hint] add --show to print the field value")
|
|
6054
|
+
return
|
|
6055
|
+
# --show: the deliberate human read-back path (terminal only; the wire
|
|
6056
|
+
# never carries these values). Counted as usage like any other reveal.
|
|
6057
|
+
if field:
|
|
6058
|
+
value = cred_store.get_value(args.name, project_path=project_path,
|
|
6059
|
+
field=field)
|
|
6060
|
+
if value is None:
|
|
6061
|
+
print(f"[error] no field '{field}' on '{args.name}'")
|
|
6062
|
+
return
|
|
6063
|
+
print(value)
|
|
6064
|
+
_creds_count_show([f"{args.name}.{field}"], project_path)
|
|
6065
|
+
else:
|
|
6066
|
+
fields = cred_store.get_structured_fields(
|
|
6067
|
+
args.name, project_path=project_path)
|
|
6068
|
+
if fields is None:
|
|
6069
|
+
print("[error] value missing from store")
|
|
6070
|
+
return
|
|
6071
|
+
width = max(len(k) for k in fields)
|
|
6072
|
+
for key in sorted(fields):
|
|
6073
|
+
print(f"{key:<{width}} {fields[key]}")
|
|
6074
|
+
_creds_count_show([args.name], project_path)
|
|
5989
6075
|
|
|
5990
6076
|
|
|
5991
6077
|
def _creds_cmd_list(args, project_path: str) -> None:
|
|
@@ -6039,6 +6125,39 @@ def _creds_cmd_import(args, project_path: str) -> None:
|
|
|
6039
6125
|
"(use --overwrite to replace)")
|
|
6040
6126
|
|
|
6041
6127
|
|
|
6128
|
+
def _creds_cmd_usage(args, project_path: str) -> None:
|
|
6129
|
+
import json as _json
|
|
6130
|
+
|
|
6131
|
+
from services import cred_telemetry as ct
|
|
6132
|
+
|
|
6133
|
+
name = getattr(args, "name", "") or ""
|
|
6134
|
+
limit = max(1, int(getattr(args, "limit", 20) or 20))
|
|
6135
|
+
agg = ct.aggregate(project_path, name=name)
|
|
6136
|
+
recent = ct.search_events(project_path, name=name, limit=limit)
|
|
6137
|
+
if getattr(args, "as_json", False):
|
|
6138
|
+
print(_json.dumps({"aggregate": agg, "recent": recent}, indent=2))
|
|
6139
|
+
return
|
|
6140
|
+
if not agg["total"]:
|
|
6141
|
+
target = f" for '{name}'" if name else ""
|
|
6142
|
+
print(f"No recorded credential uses{target} yet.")
|
|
6143
|
+
return
|
|
6144
|
+
surf = " ".join(f"{s}:{c}" for s, c in sorted(agg["by_surface"].items()))
|
|
6145
|
+
print(f"{agg['total']} use(s) across {len(agg['rows'])} credential(s)"
|
|
6146
|
+
f" [{surf}]")
|
|
6147
|
+
for row in agg["rows"]:
|
|
6148
|
+
fields = f" fields: {', '.join(row['fields'])}" if row["fields"] else ""
|
|
6149
|
+
print(f" {row['name']:<24} {row['hits']:>4}x last {row['last_ts'] or '?'}"
|
|
6150
|
+
f" projects={row['projects']}{fields}")
|
|
6151
|
+
print(f"recent (newest first, {len(recent['events'])}"
|
|
6152
|
+
f"/{recent['matched']}):")
|
|
6153
|
+
for e in recent["events"]:
|
|
6154
|
+
ref = e["name"] + (f".{e['field']}" if e.get("field") else "")
|
|
6155
|
+
exit_part = f" exit={e['exit']}" if "exit" in e else ""
|
|
6156
|
+
cmd_part = f" {e['cmd']}" if e.get("cmd") else ""
|
|
6157
|
+
print(f" {e.get('ts', '?')} {e.get('action', '?'):<10} {ref:<28}"
|
|
6158
|
+
f" [{e.get('surface', '?')}]{exit_part}{cmd_part}")
|
|
6159
|
+
|
|
6160
|
+
|
|
6042
6161
|
def cmd_ci(args):
|
|
6043
6162
|
"""AgentCI entry point — exits with the finding.
|
|
6044
6163
|
|
|
@@ -417,9 +417,14 @@ def build_parser(version: str, parse_cli_ide_arg):
|
|
|
417
417
|
"set", help="Create or update a credential (value via hidden prompt)"
|
|
418
418
|
)
|
|
419
419
|
cr_set.add_argument("name", help="Entry name (env-var safe: [A-Za-z_][A-Za-z0-9_]*)")
|
|
420
|
-
cr_set.add_argument("--value", default="", help="Secret value (prompted via getpass if omitted — preferred)")
|
|
420
|
+
cr_set.add_argument("--value", default="", help="Secret value (prompted via getpass if omitted — preferred). Structured types take a JSON object of fields")
|
|
421
421
|
cr_set.add_argument("--stdin", action="store_true", help="Read the value from stdin (piped/multiline values)")
|
|
422
|
-
cr_set.add_argument("--type", dest="ctype",
|
|
422
|
+
cr_set.add_argument("--type", dest="ctype",
|
|
423
|
+
choices=["token", "env", "multiline",
|
|
424
|
+
"address", "identity", "card"],
|
|
425
|
+
default="token",
|
|
426
|
+
help="Entry type; address/identity/card are structured "
|
|
427
|
+
"(field payload, inject-only, never revealable to the agent)")
|
|
423
428
|
cr_set.add_argument("--desc", default="", help="Human description shown in list/UI")
|
|
424
429
|
cr_set.add_argument("--env-var", default="", help="Env var name used at injection (default: entry name)")
|
|
425
430
|
cr_set.add_argument("--agent-readable", action="store_true", help="Allow the agent to reveal the decoded value into its context (default: injection-only)")
|
|
@@ -432,6 +437,7 @@ def build_parser(version: str, parse_cli_ide_arg):
|
|
|
432
437
|
cr_get = creds_subs.add_parser("get", help="Show entry metadata (masked; --show prints the value)")
|
|
433
438
|
cr_get.add_argument("name")
|
|
434
439
|
cr_get.add_argument("--show", action="store_true", help="Print the decoded value to the terminal")
|
|
440
|
+
cr_get.add_argument("--field", default="", help="For structured entries: limit --show to one field (e.g. number)")
|
|
435
441
|
cr_get.add_argument("--path", dest="project_path", default=".", help="Project directory (default: current)")
|
|
436
442
|
|
|
437
443
|
cr_list = creds_subs.add_parser("list", help="List credentials visible to this project")
|
|
@@ -448,6 +454,13 @@ def build_parser(version: str, parse_cli_ide_arg):
|
|
|
448
454
|
cr_import.add_argument("--overwrite", action="store_true", help="Replace entries already registered in the target scope")
|
|
449
455
|
cr_import.add_argument("--path", dest="project_path", default=".", help="Project directory (default: current)")
|
|
450
456
|
|
|
457
|
+
cr_usage = creds_subs.add_parser(
|
|
458
|
+
"usage", help="Usage history — when, where, and how often credentials were used")
|
|
459
|
+
cr_usage.add_argument("name", nargs="?", default="", help="Limit to one credential (default: all)")
|
|
460
|
+
cr_usage.add_argument("--limit", type=int, default=20, help="Recent events to show (default: 20)")
|
|
461
|
+
cr_usage.add_argument("--json", dest="as_json", action="store_true", help="Emit raw JSON")
|
|
462
|
+
cr_usage.add_argument("--path", dest="project_path", default=".", help="Project directory (default: current)")
|
|
463
|
+
|
|
451
464
|
# ── Agent Locks (docs/agent-locks.md) ───────────────────────────────
|
|
452
465
|
# force-release is human-only: it bumps the fencing counter so a holder
|
|
453
466
|
# that comes back is stale by construction. Agents get c3_locks instead,
|
|
@@ -266,6 +266,8 @@ c3_bitbucket(action=<span class="str">'get_pr'</span>, pr_id=<span class="num">4
|
|
|
266
266
|
<tr><td class="grp-read"><code>get_pr</code></td> <td><code>project, repo, pr_id</code></td><td>Full PR detail incl. version, reviewers, description, open-tasks</td></tr>
|
|
267
267
|
<tr><td class="grp-read"><code>get_pr_diff</code></td> <td><code>project, repo, pr_id, context_lines?</code></td><td>Unified diff (truncated to 6000 chars in the response)</td></tr>
|
|
268
268
|
<tr><td class="grp-read"><code>get_pr_activities</code></td><td><code>project, repo, pr_id</code></td><td>PR event timeline (comments, approvals, reviewer changes)</td></tr>
|
|
269
|
+
<tr><td class="grp-read"><code>get_pr_commits</code></td><td><code>project, repo, pr_id</code></td><td>Commits on the PR, newest first</td></tr>
|
|
270
|
+
<tr><td class="grp-read"><code>list_pr_tasks</code></td><td><code>project, repo, pr_id, state?</code></td><td>PR tasks (BLOCKER-severity comments); <code>state=OPEN|RESOLVED</code> filters</td></tr>
|
|
269
271
|
<tr><td class="grp-read"><code>list_branches</code></td><td><code>project, repo, filter?</code></td><td>Branches with ahead/behind counts and default-branch flag</td></tr>
|
|
270
272
|
<tr><td class="grp-read"><code>list_commits</code></td> <td><code>project, repo, branch?, path?, limit?</code></td><td>Commit log on a branch / path</td></tr>
|
|
271
273
|
<tr><td class="grp-read"><code>list_activity</code></td><td><code>project, repo, limit?</code></td><td>Repo activity feed (commit-based)</td></tr>
|
|
@@ -278,9 +280,15 @@ c3_bitbucket(action=<span class="str">'get_pr'</span>, pr_id=<span class="num">4
|
|
|
278
280
|
<thead><tr><th>Action</th><th>Args</th><th>Description</th></tr></thead>
|
|
279
281
|
<tbody>
|
|
280
282
|
<tr><td class="grp-write"><code>create_pr</code></td> <td><code>title, from_branch, to_branch, description?, reviewers?</code></td><td>Open a new PR. <code>reviewers</code> may be a list or comma-separated string.</td></tr>
|
|
283
|
+
<tr><td class="grp-write"><code>update_pr</code></td> <td><code>pr_id, title?, description?, to_branch?, reviewers?</code></td><td>Edit an open PR. Unchanged fields are merged from the live PR; the current version is auto-fetched. <code>reviewers</code> is the full replacement set.</td></tr>
|
|
281
284
|
<tr><td class="grp-write"><code>comment_pr</code></td> <td><code>pr_id, body</code></td> <td>Add a top-level comment</td></tr>
|
|
285
|
+
<tr><td class="grp-write"><code>update_pr_comment</code></td><td><code>pr_id, comment_id, body</code></td><td>Edit a comment's text. The comment's current version is auto-fetched.</td></tr>
|
|
286
|
+
<tr><td class="grp-write"><code>delete_pr_comment</code></td><td><code>pr_id, comment_id</code></td> <td>Delete a comment (version auto-fetched)</td></tr>
|
|
287
|
+
<tr><td class="grp-write"><code>create_pr_task</code></td><td><code>pr_id, body</code></td> <td>Open a task on the PR — a BLOCKER-severity comment that gates merge</td></tr>
|
|
288
|
+
<tr><td class="grp-write"><code>resolve_pr_task</code></td><td><code>pr_id, comment_id</code></td> <td>Resolve a task by its id (from <code>list_pr_tasks</code>)</td></tr>
|
|
282
289
|
<tr><td class="grp-write"><code>approve_pr</code></td> <td><code>pr_id</code></td> <td>Mark the PR approved as the current user</td></tr>
|
|
283
290
|
<tr><td class="grp-write"><code>unapprove_pr</code></td><td><code>pr_id</code></td> <td>Withdraw approval</td></tr>
|
|
291
|
+
<tr><td class="grp-write"><code>needs_work_pr</code></td><td><code>pr_id</code></td> <td>Mark the PR "needs work" as the current user (the third reviewer verdict)</td></tr>
|
|
284
292
|
<tr><td class="grp-write"><code>decline_pr</code></td> <td><code>pr_id</code></td> <td>Decline the PR. Auto-fetches the current PR version first.</td></tr>
|
|
285
293
|
<tr><td class="grp-write"><code>merge_pr</code></td> <td><code>pr_id, message?</code></td> <td>Merge the PR. Auto-fetches the current PR version first; logs to the C3 edit ledger.</td></tr>
|
|
286
294
|
</tbody>
|
|
@@ -365,9 +373,10 @@ c3_bitbucket(action=<span class="str">'get_pr'</span>, pr_id=<span class="num">4
|
|
|
365
373
|
<table class="params-table">
|
|
366
374
|
<thead><tr><th>Action</th><th>Why it's logged</th></tr></thead>
|
|
367
375
|
<tbody>
|
|
368
|
-
<tr><td><code>create_pr</code
|
|
369
|
-
<tr><td><code>comment_pr</code
|
|
370
|
-
<tr><td><code>
|
|
376
|
+
<tr><td><code>create_pr</code> / <code>update_pr</code></td><td>PR opened or its title/description/reviewers/target edited — relevant for review timeline</td></tr>
|
|
377
|
+
<tr><td><code>comment_pr</code> / <code>update_pr_comment</code> / <code>delete_pr_comment</code></td><td>Discussion contributions worth recovering on / clear</td></tr>
|
|
378
|
+
<tr><td><code>create_pr_task</code> / <code>resolve_pr_task</code></td><td>Merge-gating task opened or closed</td></tr>
|
|
379
|
+
<tr><td><code>approve_pr</code> / <code>unapprove_pr</code> / <code>needs_work_pr</code></td><td>Reviewer state changes</td></tr>
|
|
371
380
|
<tr><td><code>decline_pr</code></td> <td>PR closed without merge</td></tr>
|
|
372
381
|
<tr><td><code>merge_pr</code></td> <td>Code now lives in the target branch — high-impact</td></tr>
|
|
373
382
|
<tr><td><code>create_branch</code> / <code>delete_branch</code></td><td>Branch topology changed</td></tr>
|
|
@@ -105,11 +105,13 @@
|
|
|
105
105
|
<a href="#storage" class="sidebar-link"><span class="icon">🗄️</span> Where values live</a>
|
|
106
106
|
<a href="#scopes" class="sidebar-link"><span class="icon">🌍</span> Scopes & overriding</a>
|
|
107
107
|
<a href="#agent-use" class="sidebar-link"><span class="icon">🤖</span> How agents use them</a>
|
|
108
|
+
<a href="#structured" class="sidebar-link"><span class="icon">💳</span> Structured kinds</a>
|
|
108
109
|
<a href="#exposure" class="sidebar-link"><span class="icon">⚠️</span> Exposure flags</a>
|
|
109
110
|
<a href="#hub-ui" class="sidebar-link"><span class="icon">🖥️</span> Hub UI</a>
|
|
110
111
|
<a href="#search" class="sidebar-link"><span class="icon">🔎</span> Search & qualifiers</a>
|
|
111
112
|
<a href="#cli" class="sidebar-link"><span class="icon">💻</span> CLI commands</a>
|
|
112
113
|
<a href="#actions" class="sidebar-link"><span class="icon">⚙️</span> Tool actions</a>
|
|
114
|
+
<a href="#usage" class="sidebar-link"><span class="icon">📊</span> Usage history</a>
|
|
113
115
|
<a href="#audit" class="sidebar-link"><span class="icon">📝</span> Audit trail</a>
|
|
114
116
|
<a href="#troubleshooting" class="sidebar-link"><span class="icon">🛠️</span> Troubleshooting</a>
|
|
115
117
|
</div>
|
|
@@ -293,6 +295,48 @@ c3_shell(cmd=<span class="str">'terraform apply'</span>, env_creds=<span class="
|
|
|
293
295
|
|
|
294
296
|
<hr class="divider">
|
|
295
297
|
|
|
298
|
+
<!-- ═══════════════════════════════════ STRUCTURED ═══ -->
|
|
299
|
+
<section id="structured" class="tool-section">
|
|
300
|
+
<h2>Structured kinds — cards, addresses, identity (v2.87.0)</h2>
|
|
301
|
+
|
|
302
|
+
<p>Three entry types hold <strong>named fields</strong> instead of one opaque value:
|
|
303
|
+
<code>card</code> (cardholder, number, expiry, optional cvc/billing_zip — Luhn-checked),
|
|
304
|
+
<code>address</code> (street1, city, state, zip, optional recipient/street2/country/phone) and
|
|
305
|
+
<code>identity</code> (full_name, optional dob/ssn/phone/email). The payload is stored as one
|
|
306
|
+
canonical JSON object through the same keyring / encrypted-sidecar path as any other value.</p>
|
|
307
|
+
|
|
308
|
+
<p>They are <strong>inject-only by construction</strong>, which is stricter than a normal secret:</p>
|
|
309
|
+
<ul>
|
|
310
|
+
<li><strong>Reveal is permanently disabled</strong> — <code>agent_readable</code> and
|
|
311
|
+
<code>inject</code> are refused at every surface, for every caller, forever. There is no flag to flip.</li>
|
|
312
|
+
<li><strong>Only single fields cross the boundary.</strong> The agent addresses a field —
|
|
313
|
+
<code>env_creds='CARD.number'</code> (exported as <code>$CARD_NUMBER</code>) or
|
|
314
|
+
<code>{{cred:CARD.number}}</code> inline — and a bare <code>{{cred:CARD}}</code> fails with
|
|
315
|
+
the field list rather than expanding the whole payload.</li>
|
|
316
|
+
<li><strong>The registry shows a projection, not the data.</strong> Lists and the UI display
|
|
317
|
+
<code>visa ••••4242</code> for a card (brand + last4, deliberately <em>not</em> expiry),
|
|
318
|
+
city/state for an address, the name for an identity. Field <em>names</em> are public;
|
|
319
|
+
field <em>values</em> never transit any HTTP response — a sweep test enforces this.</li>
|
|
320
|
+
<li><strong>Echoes redact per field</strong> to <code>[cred:NAME.field]</code>. Caveat: the
|
|
321
|
+
redactor only tracks values of 4+ characters, so a 3-digit CVC or 2-letter state that a
|
|
322
|
+
child process echoes cannot be scrubbed after the fact. The real guarantee remains
|
|
323
|
+
decode-at-the-subprocess-boundary; redaction is the belt over it.</li>
|
|
324
|
+
<li><strong>The type boundary is immutable.</strong> A card cannot be rewritten into a
|
|
325
|
+
plain token (or vice versa) by <code>set</code>, metadata update, or <code>.env</code>
|
|
326
|
+
import — delete and re-create is the only path across, and a keyring attestation keeps an
|
|
327
|
+
entry structured even if <code>.c3/config.json</code> is edited by hand.</li>
|
|
328
|
+
</ul>
|
|
329
|
+
|
|
330
|
+
<p>Updating one field never requires retyping the rest: a partial payload
|
|
331
|
+
<strong>merges</strong> (<code>{"expiry": "01/30"}</code> updates the expiry, JSON
|
|
332
|
+
<code>null</code> deletes an optional field). Read-back for <em>you</em> is terminal-only:
|
|
333
|
+
<code>c3 creds get NAME --show</code> (all fields) or <code>--show --field number</code> —
|
|
334
|
+
the browser and the mobile gateway never carry the values, and mobile cannot create
|
|
335
|
+
structured entries at all.</p>
|
|
336
|
+
</section>
|
|
337
|
+
|
|
338
|
+
<hr class="divider">
|
|
339
|
+
|
|
296
340
|
<!-- ═══════════════════════════════════════ EXPOSURE ═══ -->
|
|
297
341
|
<section id="exposure" class="tool-section">
|
|
298
342
|
<h2>Exposure flags</h2>
|
|
@@ -478,6 +522,42 @@ c3_shell(cmd=<span class="str">'terraform apply'</span>, env_creds=<span class="
|
|
|
478
522
|
<hr class="divider">
|
|
479
523
|
|
|
480
524
|
<!-- ═══════════════════════════════════════ AUDIT ═══ -->
|
|
525
|
+
<section id="usage" class="tool-section">
|
|
526
|
+
<h2>Usage history (v2.88.0)</h2>
|
|
527
|
+
|
|
528
|
+
<p>Every time a value leaves the vault — an <code>env_creds</code> injection, a
|
|
529
|
+
<code>{{cred:NAME}}</code> expansion, a gated reveal, a terminal
|
|
530
|
+
<code>c3 creds get --show</code> — one event is appended to the owning scope's
|
|
531
|
+
<code>.c3/cred_usage.jsonl</code>: timestamp, name (and field for structured entries),
|
|
532
|
+
action, surface, project, exit code, and the command in its <strong>raw template
|
|
533
|
+
form</strong>, capped at 120 characters. Never the expanded string, never a value.
|
|
534
|
+
A global credential's usage from every project lands in <code>~/.c3</code>, so its
|
|
535
|
+
history is complete in one place.</p>
|
|
536
|
+
|
|
537
|
+
<p>Reading it back:</p>
|
|
538
|
+
<ul>
|
|
539
|
+
<li><strong>UI</strong> — the Credentials tab's <em>usage</em> sub-view (totals,
|
|
540
|
+
per-credential counts by surface, expandable recent events) and the hub drawer's
|
|
541
|
+
“Usage & relationships” section.</li>
|
|
542
|
+
<li><strong>CLI</strong> — <code>c3 creds usage [NAME] [--limit N] [--json]</code>.</li>
|
|
543
|
+
<li><strong>Agent</strong> — <code>c3_credentials(action='usage')</code>. Scoped on
|
|
544
|
+
purpose: the agent sees full events (including command previews) only for the
|
|
545
|
+
<em>current</em> project; other projects' use of a shared global credential is
|
|
546
|
+
reduced to counts, so one project's agent cannot read another's command lines
|
|
547
|
+
through the vault. Your surfaces (UI/CLI) show everything.</li>
|
|
548
|
+
<li><strong>REST</strong> — <code>GET /api/credentials/usage</code> and
|
|
549
|
+
<code>GET /api/credentials/<name>/usage</code> (hub:
|
|
550
|
+
<code>/api/projects/credentials/usage</code>).</li>
|
|
551
|
+
</ul>
|
|
552
|
+
|
|
553
|
+
<p>The log rotates at 512KB (one <code>.1</code> generation retained), both filenames
|
|
554
|
+
are vault-write-protected and gitignored, and the lightweight
|
|
555
|
+
<code>last_used</code>/<code>use_count</code> counters you already see on list rows
|
|
556
|
+
keep working exactly as before — they are the summary; this is the history.</p>
|
|
557
|
+
</section>
|
|
558
|
+
|
|
559
|
+
<hr class="divider">
|
|
560
|
+
|
|
481
561
|
<section id="audit" class="tool-section">
|
|
482
562
|
<h2>Audit trail</h2>
|
|
483
563
|
|
|
@@ -1217,8 +1217,10 @@ c3_artifacts(action=<span class="str">'show'</span>, artifact=<span class="str">
|
|
|
1217
1217
|
<tr><td class="param-name">status</td><td>Read</td><td class="param-desc">Active account, accounts list, defaults, server-version probe</td></tr>
|
|
1218
1218
|
<tr><td class="param-name">whoami</td><td>Read</td><td class="param-desc">Current authenticated user (PAT owner)</td></tr>
|
|
1219
1219
|
<tr><td class="param-name">list_projects, list_repos, get_repo</td><td>Read</td><td class="param-desc">Project / repository discovery</td></tr>
|
|
1220
|
-
<tr><td class="param-name">list_prs, get_pr, get_pr_diff, get_pr_activities</td><td>Read</td><td class="param-desc">PR browsing + diff + activity feed</td></tr>
|
|
1221
|
-
<tr><td class="param-name">create_pr, comment_pr, approve_pr, unapprove_pr, decline_pr, merge_pr</td><td>Write</td><td class="param-desc">PR write actions. <code>merge_pr</code> and <code>
|
|
1220
|
+
<tr><td class="param-name">list_prs, get_pr, get_pr_diff, get_pr_activities, get_pr_commits</td><td>Read</td><td class="param-desc">PR browsing + diff + activity feed + commit list</td></tr>
|
|
1221
|
+
<tr><td class="param-name">create_pr, update_pr, comment_pr, approve_pr, unapprove_pr, needs_work_pr, decline_pr, merge_pr</td><td>Write</td><td class="param-desc">PR write actions. <code>update_pr</code> edits title/description/reviewers/to_branch (unchanged fields preserved); <code>merge_pr</code>, <code>decline_pr</code>, and <code>update_pr</code> auto-fetch the PR's current version; <code>needs_work_pr</code> marks "needs work" as the current user</td></tr>
|
|
1222
|
+
<tr><td class="param-name">update_pr_comment, delete_pr_comment</td><td>Write</td><td class="param-desc">Edit or remove a PR comment by <code>comment_id</code> — the comment's current version is fetched automatically</td></tr>
|
|
1223
|
+
<tr><td class="param-name">list_pr_tasks, create_pr_task, resolve_pr_task</td><td>Tasks</td><td class="param-desc">PR tasks (Bitbucket 7.2+ model: a task is a BLOCKER-severity comment). <code>list_pr_tasks</code> filters by <code>state=OPEN|RESOLVED</code>; resolve takes the task's <code>comment_id</code></td></tr>
|
|
1222
1224
|
<tr><td class="param-name">list_branches, create_branch, delete_branch</td><td>Branch</td><td class="param-desc">Branch listing and admin (uses the <code>branch-utils</code> API)</td></tr>
|
|
1223
1225
|
<tr><td class="param-name">list_commits, list_activity, build_status</td><td>Read</td><td class="param-desc">Recent commits, activity, build/CI status (defaults to default-branch HEAD)</td></tr>
|
|
1224
1226
|
<tr><td class="param-name">repo_settings, update_repo_settings, list_webhooks, create_webhook, delete_webhook, list_permissions</td><td>Admin</td><td class="param-desc">Repository administration</td></tr>
|
|
@@ -1310,9 +1312,15 @@ c3_shell(cmd=<span class="str">'curl -H "Authorization: Bearer {{cred:API_KEY}}"
|
|
|
1310
1312
|
<tr><td class="param-name">status, whoami</td><td>Read</td><td class="param-desc">Active account, deployment, defaults, server probe / authenticated user</td></tr>
|
|
1311
1313
|
<tr><td class="param-name">search</td><td>Read</td><td class="param-desc">Raw JQL, paginated (helper-built JQL elsewhere is always quoted)</td></tr>
|
|
1312
1314
|
<tr><td class="param-name">my_issues</td><td>Read</td><td class="param-desc">Open issues assigned to the token's user (statusCategory-aware)</td></tr>
|
|
1313
|
-
<tr><td class="param-name">get_issue, list_projects, list_transitions</td><td>Read</td><td class="param-desc">Issue detail with comments / project discovery / legal transitions for an issue</td></tr>
|
|
1314
|
-
<tr><td class="param-name">get_create_metadata, search_users</td><td>Read</td><td class="param-desc">
|
|
1315
|
-
<tr><td class="param-name">
|
|
1315
|
+
<tr><td class="param-name">get_issue, list_projects, list_transitions</td><td>Read</td><td class="param-desc">Issue detail with comments, parent, and typed links / project discovery / legal transitions for an issue</td></tr>
|
|
1316
|
+
<tr><td class="param-name">get_create_metadata, search_users, list_link_types</td><td>Read</td><td class="param-desc">Field configuration per project/type (ids + names; the create screen may accept fewer — Jira over-reports, Epic Link is the classic case); user lookup for assignment; the server's issue-link type catalog</td></tr>
|
|
1317
|
+
<tr><td class="param-name">list_boards, list_sprints, list_worklogs</td><td>Read</td><td class="param-desc">Agile boards (project fallback applies) → sprints per board (<code>sprint_state=active|future|closed</code>); an issue's logged time</td></tr>
|
|
1318
|
+
<tr><td class="param-name">move_to_sprint, move_to_backlog</td><td>Write</td><td class="param-desc">Sprint assignment via the Agile API — <code>issue</code> takes one key or a comma-list; <code>sprint_id</code> comes from <code>list_sprints</code></td></tr>
|
|
1319
|
+
<tr><td class="param-name">add_worklog, attach_file</td><td>Write</td><td class="param-desc">Log time (<code>time_spent='2h 30m'</code>, optional <code>body</code> comment); upload one local file as an attachment (20MB local cap)</td></tr>
|
|
1320
|
+
<tr><td class="param-name">unlink_issues, delete_issue</td><td>Write</td><td class="param-desc">Remove a typed link by <code>link_id</code> (shown on get_issue); permanently delete an issue — refuses one with subtasks unless <code>delete_subtasks=true</code></td></tr>
|
|
1321
|
+
<tr><td class="param-name">create_issue</td><td>Write</td><td class="param-desc">Pre-validates against create metadata and returns machine-readable missing required fields instead of guessing defaults. <code>parent=EPIC-KEY</code> files the new issue under an epic (deployment-mapped)</td></tr>
|
|
1322
|
+
<tr><td class="param-name">update_issue</td><td>Write</td><td class="param-desc">Edit an existing issue: summary, description, <code>parent</code> (epic/parent key; <code>'none'</code> clears), or a fields JSON of field ids → values — the fallback when the create screen rejects a field ("not on the appropriate screen")</td></tr>
|
|
1323
|
+
<tr><td class="param-name">link_issues</td><td>Write</td><td class="param-desc">Typed link reading <code><issue> <link_type> <target></code> — accepts a type name or either directional phrasing (an inward match flips the pair); unknown types answer with the catalog</td></tr>
|
|
1316
1324
|
<tr><td class="param-name">comment, transition, assign</td><td>Write</td><td class="param-desc">Comment on / move (accepts transition id <em>or</em> name) / assign an issue</td></tr>
|
|
1317
1325
|
</tbody>
|
|
1318
1326
|
</table>
|
|
@@ -1330,12 +1338,31 @@ c3_jira(action=<span class="str">'get_create_metadata'</span>, project=<span cla
|
|
|
1330
1338
|
c3_jira(action=<span class="str">'create_issue'</span>, project=<span class="str">'PROJ'</span>, issue_type=<span class="str">'Task'</span>,
|
|
1331
1339
|
summary=<span class="str">'Fix login flow'</span>, description=<span class="str">'Steps in thread'</span>)
|
|
1332
1340
|
|
|
1341
|
+
<span class="com"># Field rejected on create ("not on the appropriate screen")? Set it post-create</span>
|
|
1342
|
+
c3_jira(action=<span class="str">'update_issue'</span>, issue=<span class="str">'PROJ-124'</span>, fields=<span class="str">'{"customfield_10014": "PROJ-42"}'</span>)
|
|
1343
|
+
|
|
1344
|
+
<span class="com"># Put an issue under an epic — no customfield hunting (Cloud parent field
|
|
1345
|
+
# vs Data Center Epic Link customfield is resolved for you)</span>
|
|
1346
|
+
c3_jira(action=<span class="str">'update_issue'</span>, issue=<span class="str">'PROJ-124'</span>, parent=<span class="str">'PROJ-42'</span>)
|
|
1347
|
+
|
|
1348
|
+
<span class="com"># Typed links: reads "PROJ-1 blocks PROJ-2"</span>
|
|
1349
|
+
c3_jira(action=<span class="str">'link_issues'</span>, issue=<span class="str">'PROJ-1'</span>, link_type=<span class="str">'blocks'</span>, target=<span class="str">'PROJ-2'</span>)
|
|
1350
|
+
|
|
1351
|
+
<span class="com"># Sprint flow: board -> sprint -> assign</span>
|
|
1352
|
+
c3_jira(action=<span class="str">'list_boards'</span>)
|
|
1353
|
+
c3_jira(action=<span class="str">'list_sprints'</span>, board_id=<span class="num">7</span>, sprint_state=<span class="str">'active'</span>)
|
|
1354
|
+
c3_jira(action=<span class="str">'move_to_sprint'</span>, issue=<span class="str">'PROJ-1, PROJ-2'</span>, sprint_id=<span class="num">42</span>)
|
|
1355
|
+
|
|
1356
|
+
<span class="com"># Time + evidence</span>
|
|
1357
|
+
c3_jira(action=<span class="str">'add_worklog'</span>, issue=<span class="str">'PROJ-1'</span>, time_spent=<span class="str">'2h 30m'</span>, body=<span class="str">'pairing'</span>)
|
|
1358
|
+
c3_jira(action=<span class="str">'attach_file'</span>, issue=<span class="str">'PROJ-1'</span>, file_path=<span class="str">'logs/build.log'</span>)
|
|
1359
|
+
|
|
1333
1360
|
<span class="com"># Move it along — id or name both work</span>
|
|
1334
1361
|
c3_jira(action=<span class="str">'list_transitions'</span>, issue=<span class="str">'PROJ-123'</span>)
|
|
1335
1362
|
c3_jira(action=<span class="str">'transition'</span>, issue=<span class="str">'PROJ-123'</span>, transition=<span class="str">'In Progress'</span>)
|
|
1336
1363
|
c3_jira(action=<span class="str">'comment'</span>, issue=<span class="str">'PROJ-123'</span>, body=<span class="str">'Deployed to staging'</span>)</code></pre>
|
|
1337
1364
|
|
|
1338
|
-
<p class="tool-desc"><strong>Surfaces & audit:</strong> the per-project dashboard gets a <strong>Jira tab</strong> (My Work board grouped by statusCategory, JQL search, an issue drawer with transition buttons + comments, and an Activity view) backed by <code>/api/jira/*</code> routes. Issue keys like <code>PROJ-123</code> are auto-linked from branch names and edit-ledger entries (acronym denylist, so UTF-8 / SHA-256 / CVE-2024 never match), and the issue drawer shows the local ledger activity for the open issue — that Activity view works with no account configured. Mutations (<code>create_issue</code>, <code>comment</code>, <code>transition</code>, <code>assign</code>) are edit-ledger-logged with identifiers only — bodies are never logged. Read actions are safe in plan mode.</p>
|
|
1365
|
+
<p class="tool-desc"><strong>Surfaces & audit:</strong> the per-project dashboard gets a <strong>Jira tab</strong> (My Work board grouped by statusCategory, JQL search, an issue drawer with transition buttons + comments, and an Activity view) backed by <code>/api/jira/*</code> routes. Issue keys like <code>PROJ-123</code> are auto-linked from branch names and edit-ledger entries (acronym denylist, so UTF-8 / SHA-256 / CVE-2024 never match), and the issue drawer shows the local ledger activity for the open issue — that Activity view works with no account configured. Mutations (<code>create_issue</code>, <code>update_issue</code>, <code>comment</code>, <code>transition</code>, <code>assign</code>, <code>link_issues</code>, <code>unlink_issues</code>, <code>move_to_sprint</code>, <code>move_to_backlog</code>, <code>add_worklog</code>, <code>attach_file</code>, <code>delete_issue</code>) are edit-ledger-logged with identifiers only — bodies are never logged. Read actions are safe in plan mode.</p>
|
|
1339
1366
|
</div>
|
|
1340
1367
|
</div>
|
|
1341
1368
|
</div>
|
|
@@ -113,7 +113,8 @@ _WRITE_CLASS_ALWAYS = frozenset({"Edit", "Write", "MultiEdit"})
|
|
|
113
113
|
# Vault files no native write may touch, regardless of unlock state.
|
|
114
114
|
# Mirrors services.credential_store.VAULT_PROTECTED_FILES (parity-tested);
|
|
115
115
|
# duplicated because hooks must stay import-light.
|
|
116
|
-
_VAULT_FILES = frozenset({"config.json", "secrets.enc", "cred_state.json"
|
|
116
|
+
_VAULT_FILES = frozenset({"config.json", "secrets.enc", "cred_state.json",
|
|
117
|
+
"cred_usage.jsonl", "cred_usage.jsonl.1"})
|
|
117
118
|
|
|
118
119
|
# Redirect messages per native tool
|
|
119
120
|
_REDIRECTS = {
|
|
@@ -2026,7 +2026,9 @@ def api_projects_credentials_set():
|
|
|
2026
2026
|
str(data.get("path") or "").strip(), scope, mutation=True)
|
|
2027
2027
|
if err:
|
|
2028
2028
|
return err
|
|
2029
|
-
value =
|
|
2029
|
+
value = data.get("value")
|
|
2030
|
+
# Structured kinds submit a field OBJECT; the store takes JSON text.
|
|
2031
|
+
value = json.dumps(value) if isinstance(value, dict) else str(value or "")
|
|
2030
2032
|
ctype = str(data.get("type") or data.get("ctype") or "token")
|
|
2031
2033
|
try:
|
|
2032
2034
|
if value:
|
|
@@ -2123,11 +2125,40 @@ def api_projects_credentials_check(name):
|
|
|
2123
2125
|
"name": name,
|
|
2124
2126
|
"scope": entry["scope"],
|
|
2125
2127
|
"storage": entry.get("storage", "keyring"),
|
|
2126
|
-
|
|
2128
|
+
# is_resolvable, not get_value: a structured entry never resolves
|
|
2129
|
+
# whole, but its payload being decodable is what "check" asks.
|
|
2130
|
+
"resolvable": cred_store.is_resolvable(name, project_path=store_path),
|
|
2127
2131
|
"fingerprint": cred_store.fingerprint(name, project_path=store_path),
|
|
2128
2132
|
})
|
|
2129
2133
|
|
|
2130
2134
|
|
|
2135
|
+
@app.route("/api/projects/credentials/usage", methods=["GET"])
|
|
2136
|
+
def api_projects_credentials_usage():
|
|
2137
|
+
"""Usage history — `path` scopes to a project (merged view); omit it for
|
|
2138
|
+
the global vault only. `name` filters to one credential. Names, counts
|
|
2139
|
+
and cmd previews only; never values."""
|
|
2140
|
+
from services import cred_telemetry as ct
|
|
2141
|
+
from services import credential_store as cred_store
|
|
2142
|
+
path = (request.args.get("path") or "").strip()
|
|
2143
|
+
if path:
|
|
2144
|
+
try:
|
|
2145
|
+
base = str(_resolve_project_path(path))
|
|
2146
|
+
except ValueError as e:
|
|
2147
|
+
return jsonify({"error": str(e)}), 404
|
|
2148
|
+
else:
|
|
2149
|
+
home = cred_store.global_base()
|
|
2150
|
+
if home is None:
|
|
2151
|
+
return jsonify({"error": "global scope unresolvable"}), 500
|
|
2152
|
+
base = str(home)
|
|
2153
|
+
name = (request.args.get("name") or "").strip()
|
|
2154
|
+
return jsonify({
|
|
2155
|
+
"path": base if path else "",
|
|
2156
|
+
"aggregate": ct.aggregate(base, name=name),
|
|
2157
|
+
"recent": ct.search_events(base, name=name,
|
|
2158
|
+
limit=request.args.get("limit", 100)),
|
|
2159
|
+
})
|
|
2160
|
+
|
|
2161
|
+
|
|
2131
2162
|
@app.route("/api/hub/credentials/overview", methods=["GET"])
|
|
2132
2163
|
def api_hub_credentials_overview():
|
|
2133
2164
|
"""Cross-project credential inventory: the global vault plus each
|
{code_context_control-2.86.0 → code_context_control-2.89.0}/cli/hub_ui/components/drill_panel.js
RENAMED
|
@@ -182,8 +182,8 @@ function DrillPanel({ project, tab, setTab, onClose, onChanged, onOpenModal, pro
|
|
|
182
182
|
</button>
|
|
183
183
|
</div>
|
|
184
184
|
<div style={{
|
|
185
|
-
display: 'flex', gap: 2, padding: '4px 20px 0',
|
|
186
|
-
borderBottom: `1px solid ${T.border}`,
|
|
185
|
+
display: 'flex', flexWrap: 'wrap', gap: 2, padding: '4px 20px 0',
|
|
186
|
+
borderBottom: `1px solid ${T.border}`, flexShrink: 0,
|
|
187
187
|
}}>
|
|
188
188
|
{tabs.map(([id, label]) => (
|
|
189
189
|
<button key={id} onClick={() => setTab(id)} style={{
|