code-context-control 2.46.0__tar.gz → 2.49.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.46.0/code_context_control.egg-info → code_context_control-2.49.0}/PKG-INFO +1 -1
- {code_context_control-2.46.0 → code_context_control-2.49.0}/cli/c3.py +11 -3
- {code_context_control-2.46.0 → code_context_control-2.49.0}/cli/commands/parser.py +10 -1
- {code_context_control-2.46.0 → code_context_control-2.49.0}/cli/tools/compress.py +1 -2
- {code_context_control-2.46.0 → code_context_control-2.49.0}/cli/tools/federate.py +0 -1
- {code_context_control-2.46.0 → code_context_control-2.49.0}/cli/tools/filter.py +1 -2
- {code_context_control-2.46.0 → code_context_control-2.49.0}/cli/tools/read.py +1 -2
- {code_context_control-2.46.0 → code_context_control-2.49.0}/cli/tools/search.py +1 -2
- {code_context_control-2.46.0 → code_context_control-2.49.0/code_context_control.egg-info}/PKG-INFO +1 -1
- {code_context_control-2.46.0 → code_context_control-2.49.0}/code_context_control.egg-info/SOURCES.txt +29 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/oracle/config.py +11 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/oracle/oracle.html +46 -1
- {code_context_control-2.46.0 → code_context_control-2.49.0}/oracle/oracle_server.py +132 -18
- code_context_control-2.49.0/oracle/oracle_ui.html +1215 -0
- code_context_control-2.49.0/oracle/services/c3_bridge.py +372 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/oracle/services/chat_engine.py +453 -141
- {code_context_control-2.46.0 → code_context_control-2.49.0}/oracle/services/federated_graph.py +52 -2
- code_context_control-2.49.0/oracle/services/local_session.py +54 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/oracle/services/ollama_bridge.py +87 -7
- {code_context_control-2.46.0 → code_context_control-2.49.0}/oracle/services/project_scanner.py +60 -6
- {code_context_control-2.46.0 → code_context_control-2.49.0}/oracle/services/review_agent.py +84 -1
- {code_context_control-2.46.0 → code_context_control-2.49.0}/oracle/services/tool_registry.py +82 -3
- code_context_control-2.49.0/oracle/ui/activity.js +101 -0
- code_context_control-2.49.0/oracle/ui/agents.js +108 -0
- code_context_control-2.49.0/oracle/ui/app.js +9 -0
- code_context_control-2.49.0/oracle/ui/busy.js +102 -0
- code_context_control-2.49.0/oracle/ui/chat/conversations.js +153 -0
- code_context_control-2.49.0/oracle/ui/chat/input.js +284 -0
- code_context_control-2.49.0/oracle/ui/chat/markdown.js +33 -0
- code_context_control-2.49.0/oracle/ui/chat/send.js +281 -0
- code_context_control-2.49.0/oracle/ui/chat/stream_renderer.js +767 -0
- code_context_control-2.49.0/oracle/ui/chat/toolbar.js +270 -0
- code_context_control-2.49.0/oracle/ui/core.js +60 -0
- code_context_control-2.49.0/oracle/ui/crossgraph.js +184 -0
- code_context_control-2.49.0/oracle/ui/header.js +69 -0
- code_context_control-2.49.0/oracle/ui/insights.js +52 -0
- code_context_control-2.49.0/oracle/ui/projects.js +245 -0
- code_context_control-2.49.0/oracle/ui/settings.js +186 -0
- code_context_control-2.49.0/oracle/ui/suggestions.js +47 -0
- code_context_control-2.49.0/oracle/ui/theme_tabs.js +52 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/pyproject.toml +5 -1
- {code_context_control-2.46.0 → code_context_control-2.49.0}/services/project_runtime.py +16 -3
- {code_context_control-2.46.0 → code_context_control-2.49.0}/services/subprojects.py +7 -4
- {code_context_control-2.46.0 → code_context_control-2.49.0}/services/task_store.py +1 -1
- code_context_control-2.49.0/tests/test_c3_bridge_project_artifacts.py +153 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/tests/test_federated_graph.py +83 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/tests/test_ghost_generation.py +2 -1
- {code_context_control-2.46.0 → code_context_control-2.49.0}/tests/test_oracle_apikey_api.py +8 -2
- code_context_control-2.49.0/tests/test_oracle_c3_bridge.py +174 -0
- code_context_control-2.49.0/tests/test_oracle_chat_engine.py +551 -0
- code_context_control-2.49.0/tests/test_oracle_local_auth.py +228 -0
- code_context_control-2.49.0/tests/test_oracle_ollama_bridge.py +203 -0
- code_context_control-2.49.0/tests/test_oracle_scanner_cache.py +94 -0
- code_context_control-2.49.0/tests/test_oracle_subproject_awareness.py +131 -0
- code_context_control-2.49.0/tests/test_oracle_ui_bundle.py +89 -0
- code_context_control-2.49.0/tests/test_review_digest.py +184 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/tests/test_tool_registry.py +32 -0
- code_context_control-2.46.0/oracle/services/c3_bridge.py +0 -237
- {code_context_control-2.46.0 → code_context_control-2.49.0}/LICENSE +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/README.md +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/cli/__init__.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/cli/_hook_utils.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/cli/commands/__init__.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/cli/commands/common.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/cli/docs.html +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/cli/edits.html +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/cli/guide/bitbucket.html +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/cli/guide/getting-started.html +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/cli/guide/index.html +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/cli/guide/oracle.html +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/cli/guide/shared.css +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/cli/guide/tools.html +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/cli/guide/workflow.html +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/cli/hook_artifact.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/cli/hook_auto_snapshot.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/cli/hook_c3_signal.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/cli/hook_c3read.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/cli/hook_dispatch.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/cli/hook_edit_ledger.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/cli/hook_edit_unlock.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/cli/hook_filter.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/cli/hook_ghost_files.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/cli/hook_pretool_enforce.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/cli/hook_read.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/cli/hook_session_stats.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/cli/hook_terse_advisor.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/cli/hub.html +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/cli/hub_server.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/cli/hub_ui/app.js +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/cli/hub_ui/components/add_project.js +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/cli/hub_ui/components/config_editor.js +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/cli/hub_ui/components/drill_artifacts.js +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/cli/hub_ui/components/drill_health.js +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/cli/hub_ui/components/drill_panel.js +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/cli/hub_ui/components/drill_tasks.js +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/cli/hub_ui/components/drill_views.js +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/cli/hub_ui/components/global_search.js +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/cli/hub_ui/components/mcp_manager.js +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/cli/hub_ui/components/modals.js +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/cli/hub_ui/components/project_card.js +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/cli/hub_ui/components/project_tree.js +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/cli/hub_ui/components/session_drawer.js +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/cli/hub_ui/components/settings_modal.js +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/cli/hub_ui/components/sidebar.js +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/cli/hub_ui/components/summary_bar.js +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/cli/hub_ui/components/task_board.js +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/cli/hub_ui/components/toasts.js +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/cli/hub_ui/components/topbar.js +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/cli/hub_ui/state.js +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/cli/hub_ui.html +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/cli/mcp_proxy.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/cli/mcp_server.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/cli/server.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/cli/tools/__init__.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/cli/tools/_helpers.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/cli/tools/agent.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/cli/tools/artifacts.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/cli/tools/bitbucket.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/cli/tools/delegate.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/cli/tools/edit.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/cli/tools/edits.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/cli/tools/impact.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/cli/tools/memory.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/cli/tools/project.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/cli/tools/session.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/cli/tools/shell.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/cli/tools/status.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/cli/tools/tasks.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/cli/tools/validate.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/cli/ui/api.js +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/cli/ui/app.js +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/cli/ui/components/bitbucket.js +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/cli/ui/components/chat.js +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/cli/ui/components/dashboard.js +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/cli/ui/components/edits.js +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/cli/ui/components/instructions.js +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/cli/ui/components/memory.js +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/cli/ui/components/sessions.js +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/cli/ui/components/settings.js +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/cli/ui/components/sidebar.js +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/cli/ui/components/tasks.js +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/cli/ui/icons.js +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/cli/ui/pm_shared.js +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/cli/ui/shared.js +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/cli/ui/theme.js +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/cli/ui.html +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/cli/ui_legacy.html +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/cli/ui_nano.html +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/code_context_control.egg-info/dependency_links.txt +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/code_context_control.egg-info/entry_points.txt +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/code_context_control.egg-info/requires.txt +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/code_context_control.egg-info/top_level.txt +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/core/__init__.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/core/config.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/core/ide.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/core/mcp_toml.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/core/web_security.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/oracle/__init__.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/oracle/mcp_oracle.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/oracle/services/__init__.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/oracle/services/activity_reporter.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/oracle/services/api_auth.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/oracle/services/chat_store.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/oracle/services/cross_memory.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/oracle/services/health_checker.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/oracle/services/insight_engine.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/oracle/services/memory_reader.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/oracle/services/memory_writer.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/oracle/services/tool_executor.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/services/__init__.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/services/activity_log.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/services/agent_base.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/services/agents.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/services/artifact_defs.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/services/artifact_store.py +1 -1
- {code_context_control-2.46.0 → code_context_control-2.49.0}/services/auto_memory.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/services/bench/__init__.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/services/bench/external/__init__.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/services/bench/external/aider_polyglot.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/services/bench/external/swe_bench.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/services/benchmark_dashboard.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/services/bitbucket_client.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/services/bitbucket_credentials.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/services/circuit_breaker.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/services/claude_md.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/services/compressor.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/services/context_snapshot.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/services/conversation_store.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/services/doc_index.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/services/e2e_benchmark.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/services/e2e_evaluator.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/services/e2e_tasks.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/services/edit_ledger.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/services/embedding_index.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/services/error_reporting.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/services/file_memory.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/services/git_context.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/services/hub_service.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/services/indexer.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/services/memory.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/services/memory_consolidator.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/services/memory_graph.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/services/memory_grounder.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/services/memory_scorer.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/services/metrics.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/services/notifications.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/services/ollama_client.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/services/output_filter.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/services/parser.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/services/project_manager.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/services/protocol.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/services/proxy_state.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/services/retention.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/services/retrieval_broker.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/services/router.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/services/runtime.py +1 -1
- {code_context_control-2.46.0 → code_context_control-2.49.0}/services/session_benchmark.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/services/session_manager.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/services/session_preloader.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/services/telemetry.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/services/text_index.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/services/tool_classifier.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/services/transcript_index.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/services/validation_cache.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/services/vector_store.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/services/watcher.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/services/win_subprocess.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/setup.cfg +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/tests/test_activity_reporter.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/tests/test_aider_polyglot.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/tests/test_artifact_store.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/tests/test_artifact_tool.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/tests/test_bitbucket_cli_smoke.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/tests/test_bitbucket_client.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/tests/test_bitbucket_config_fallback.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/tests/test_bitbucket_credentials.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/tests/test_bitbucket_tool.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/tests/test_c3_shell.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/tests/test_circuit_breaker.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/tests/test_claude_md_merge.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/tests/test_cli_smoke.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/tests/test_compressor_large_file.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/tests/test_delegate_cascade.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/tests/test_e2e_benchmark.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/tests/test_edit_ledger_hook.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/tests/test_edit_normalization.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/tests/test_enforcement_flip.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/tests/test_filter_backoff.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/tests/test_ghost_files.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/tests/test_git_branch_awareness.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/tests/test_hook_dispatch.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/tests/test_hook_pretool_enforce.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/tests/test_hook_smoke.py +1 -1
- {code_context_control-2.46.0 → code_context_control-2.49.0}/tests/test_hook_state.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/tests/test_hub_inspect_api.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/tests/test_hub_server_smoke.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/tests/test_install_mcp_entrypoint.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/tests/test_lazy_store_init.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/tests/test_mcp_host_guard.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/tests/test_mcp_server_smoke.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/tests/test_mcp_toml.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/tests/test_memory_graph_api.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/tests/test_memory_system.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/tests/test_notification_dedup.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/tests/test_notification_discipline.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/tests/test_oracle_api_auth.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/tests/test_oracle_discovery_api.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/tests/test_oracle_security_fixes.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/tests/test_output_filter.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/tests/test_permissions.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/tests/test_pm_api.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/tests/test_project_manager.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/tests/test_project_manager_merge.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/tests/test_project_tool.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/tests/test_read_coercion.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/tests/test_response_boilerplate.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/tests/test_retention.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/tests/test_service_durability.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/tests/test_session_benchmark.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/tests/test_session_budget.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/tests/test_shell_robustness.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/tests/test_subproject_exclusion.py +1 -1
- {code_context_control-2.46.0 → code_context_control-2.49.0}/tests/test_subproject_federation.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/tests/test_subprojects.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/tests/test_swe_bench.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/tests/test_task_store.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/tests/test_task_tool.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/tests/test_token_telemetry.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/tests/test_upgrade_and_version.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/tests/test_validate.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/tests/test_web_security.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/tests/test_windows_reliability.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/tui/__init__.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/tui/backend.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/tui/main.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/tui/screens/__init__.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/tui/screens/benchmark_view.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/tui/screens/claudemd_view.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/tui/screens/compress_view.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/tui/screens/index_view.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/tui/screens/init_view.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/tui/screens/mcp_view.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/tui/screens/optimize_view.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/tui/screens/pipe_view.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/tui/screens/projects_view.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/tui/screens/search_view.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/tui/screens/session_view.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/tui/screens/stats.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/tui/screens/ui_view.py +0 -0
- {code_context_control-2.46.0 → code_context_control-2.49.0}/tui/theme.tcss +0 -0
{code_context_control-2.46.0/code_context_control.egg-info → code_context_control-2.49.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.49.0
|
|
4
4
|
Summary: Local code-intelligence layer for AI coding tools (Claude Code, Codex, Gemini, Copilot). Retrieve less, read less, edit safer — and version the configs that shape your agent (CLAUDE.md, skills, hooks, MCP).
|
|
5
5
|
Author-email: Dimitri Tselenchuk <dtselenc@gmail.com>
|
|
6
6
|
License-Expression: Apache-2.0
|
|
@@ -85,7 +85,7 @@ console = Console() if HAS_RICH else None
|
|
|
85
85
|
# Config
|
|
86
86
|
CONFIG_DIR = ".c3"
|
|
87
87
|
CONFIG_FILE = ".c3/config.json"
|
|
88
|
-
__version__ = "2.
|
|
88
|
+
__version__ = "2.49.0"
|
|
89
89
|
|
|
90
90
|
|
|
91
91
|
def _command_deps() -> CommandDeps:
|
|
@@ -5632,10 +5632,18 @@ def _bb_cmd_set_default(args, project_path: str) -> None:
|
|
|
5632
5632
|
|
|
5633
5633
|
|
|
5634
5634
|
def cmd_oracle(args):
|
|
5635
|
-
"""Oracle Discovery API key
|
|
5635
|
+
"""Oracle dashboard server + Discovery API key management."""
|
|
5636
5636
|
sub = getattr(args, "oracle_cmd", None)
|
|
5637
|
+
if sub in ("serve", "start"):
|
|
5638
|
+
# Lazy import: run_oracle builds all Oracle services (matches
|
|
5639
|
+
# cmd_hub's deferred-import style so bare `c3` stays fast).
|
|
5640
|
+
from oracle.oracle_server import run_oracle
|
|
5641
|
+
run_oracle(port=getattr(args, "port", None),
|
|
5642
|
+
open_browser=not getattr(args, "no_browser", False))
|
|
5643
|
+
return
|
|
5637
5644
|
if sub != "api":
|
|
5638
|
-
print("Usage: c3 oracle
|
|
5645
|
+
print("Usage: c3 oracle {serve,api} — serve: launch the dashboard; "
|
|
5646
|
+
"api {info,key,rotate,clear}: manage the Discovery key")
|
|
5639
5647
|
return
|
|
5640
5648
|
|
|
5641
5649
|
from oracle.config import load_config
|
|
@@ -357,9 +357,18 @@ def build_parser(version: str, parse_cli_ide_arg):
|
|
|
357
357
|
# ── Oracle Discovery API (v2.32.0) ──────────────────────────────────
|
|
358
358
|
p_oracle = subparsers.add_parser(
|
|
359
359
|
"oracle",
|
|
360
|
-
help="Oracle Discovery API key
|
|
360
|
+
help="Oracle dashboard server + Discovery API key management",
|
|
361
361
|
)
|
|
362
362
|
or_subs = p_oracle.add_subparsers(dest="oracle_cmd")
|
|
363
|
+
or_serve = or_subs.add_parser(
|
|
364
|
+
"serve",
|
|
365
|
+
aliases=["start"],
|
|
366
|
+
help="Launch the Oracle dashboard server (REST + MCP discovery endpoints)",
|
|
367
|
+
)
|
|
368
|
+
or_serve.add_argument("--port", type=int, default=None,
|
|
369
|
+
help="Server port (default: config 'port', 3331)")
|
|
370
|
+
or_serve.add_argument("--no-browser", action="store_true",
|
|
371
|
+
help="Don't open the browser")
|
|
363
372
|
or_api = or_subs.add_parser(
|
|
364
373
|
"api",
|
|
365
374
|
help="Show connection info / manage the Discovery API key",
|
|
@@ -8,9 +8,8 @@ import sys
|
|
|
8
8
|
from concurrent.futures import ThreadPoolExecutor, as_completed
|
|
9
9
|
from pathlib import Path
|
|
10
10
|
|
|
11
|
-
from core import count_tokens
|
|
12
|
-
|
|
13
11
|
from cli.tools._helpers import finalize_with_tokens, show_token_ratios
|
|
12
|
+
from core import count_tokens
|
|
14
13
|
|
|
15
14
|
|
|
16
15
|
def _run_memory_mcp_cli(args: list, cwd: str, timeout: int = 30) -> tuple:
|
|
@@ -7,7 +7,6 @@ unions child facts. Results stay in per-scope sections — TF-IDF scores are
|
|
|
7
7
|
not comparable across corpora, so no interleaved ranking.
|
|
8
8
|
"""
|
|
9
9
|
|
|
10
|
-
from pathlib import Path
|
|
11
10
|
|
|
12
11
|
# Budget split for scope='all': the parent keeps the lion's share.
|
|
13
12
|
_PARENT_BUDGET_SHARE = 0.6
|
|
@@ -10,9 +10,8 @@ import json
|
|
|
10
10
|
import re
|
|
11
11
|
from pathlib import Path
|
|
12
12
|
|
|
13
|
-
from core import count_tokens
|
|
14
|
-
|
|
15
13
|
from cli.tools._helpers import finalize_with_tokens, show_token_ratios
|
|
14
|
+
from core import count_tokens
|
|
16
15
|
|
|
17
16
|
|
|
18
17
|
def handle_filter(file_path: str, text: str, pattern: str, max_lines: int,
|
|
@@ -6,9 +6,8 @@ from concurrent.futures import ThreadPoolExecutor, as_completed
|
|
|
6
6
|
from pathlib import Path
|
|
7
7
|
from typing import Any
|
|
8
8
|
|
|
9
|
-
from core import count_tokens
|
|
10
|
-
|
|
11
9
|
from cli.tools._helpers import finalize_with_tokens
|
|
10
|
+
from core import count_tokens
|
|
12
11
|
|
|
13
12
|
|
|
14
13
|
def _coerce_list(val: Any) -> list[str] | None:
|
|
@@ -5,9 +5,8 @@ import time
|
|
|
5
5
|
from concurrent.futures import ThreadPoolExecutor, as_completed
|
|
6
6
|
from pathlib import Path
|
|
7
7
|
|
|
8
|
-
from core import count_tokens
|
|
9
|
-
|
|
10
8
|
from cli.tools._helpers import finalize_with_tokens, show_token_ratios
|
|
9
|
+
from core import count_tokens
|
|
11
10
|
|
|
12
11
|
# Hard cap: responses above this are truncated to avoid filling context.
|
|
13
12
|
_RESPONSE_TOKEN_CAP = 2400
|
{code_context_control-2.46.0 → code_context_control-2.49.0/code_context_control.egg-info}/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.49.0
|
|
4
4
|
Summary: Local code-intelligence layer for AI coding tools (Claude Code, Codex, Gemini, Copilot). Retrieve less, read less, edit safer — and version the configs that shape your agent (CLAUDE.md, skills, hooks, MCP).
|
|
5
5
|
Author-email: Dimitri Tselenchuk <dtselenc@gmail.com>
|
|
6
6
|
License-Expression: Apache-2.0
|
|
@@ -112,6 +112,7 @@ oracle/config.py
|
|
|
112
112
|
oracle/mcp_oracle.py
|
|
113
113
|
oracle/oracle.html
|
|
114
114
|
oracle/oracle_server.py
|
|
115
|
+
oracle/oracle_ui.html
|
|
115
116
|
oracle/services/__init__.py
|
|
116
117
|
oracle/services/activity_reporter.py
|
|
117
118
|
oracle/services/api_auth.py
|
|
@@ -122,6 +123,7 @@ oracle/services/cross_memory.py
|
|
|
122
123
|
oracle/services/federated_graph.py
|
|
123
124
|
oracle/services/health_checker.py
|
|
124
125
|
oracle/services/insight_engine.py
|
|
126
|
+
oracle/services/local_session.py
|
|
125
127
|
oracle/services/memory_reader.py
|
|
126
128
|
oracle/services/memory_writer.py
|
|
127
129
|
oracle/services/ollama_bridge.py
|
|
@@ -129,6 +131,24 @@ oracle/services/project_scanner.py
|
|
|
129
131
|
oracle/services/review_agent.py
|
|
130
132
|
oracle/services/tool_executor.py
|
|
131
133
|
oracle/services/tool_registry.py
|
|
134
|
+
oracle/ui/activity.js
|
|
135
|
+
oracle/ui/agents.js
|
|
136
|
+
oracle/ui/app.js
|
|
137
|
+
oracle/ui/busy.js
|
|
138
|
+
oracle/ui/core.js
|
|
139
|
+
oracle/ui/crossgraph.js
|
|
140
|
+
oracle/ui/header.js
|
|
141
|
+
oracle/ui/insights.js
|
|
142
|
+
oracle/ui/projects.js
|
|
143
|
+
oracle/ui/settings.js
|
|
144
|
+
oracle/ui/suggestions.js
|
|
145
|
+
oracle/ui/theme_tabs.js
|
|
146
|
+
oracle/ui/chat/conversations.js
|
|
147
|
+
oracle/ui/chat/input.js
|
|
148
|
+
oracle/ui/chat/markdown.js
|
|
149
|
+
oracle/ui/chat/send.js
|
|
150
|
+
oracle/ui/chat/stream_renderer.js
|
|
151
|
+
oracle/ui/chat/toolbar.js
|
|
132
152
|
services/__init__.py
|
|
133
153
|
services/activity_log.py
|
|
134
154
|
services/agent_base.py
|
|
@@ -199,6 +219,7 @@ tests/test_bitbucket_client.py
|
|
|
199
219
|
tests/test_bitbucket_config_fallback.py
|
|
200
220
|
tests/test_bitbucket_credentials.py
|
|
201
221
|
tests/test_bitbucket_tool.py
|
|
222
|
+
tests/test_c3_bridge_project_artifacts.py
|
|
202
223
|
tests/test_c3_shell.py
|
|
203
224
|
tests/test_circuit_breaker.py
|
|
204
225
|
tests/test_claude_md_merge.py
|
|
@@ -231,8 +252,15 @@ tests/test_notification_dedup.py
|
|
|
231
252
|
tests/test_notification_discipline.py
|
|
232
253
|
tests/test_oracle_api_auth.py
|
|
233
254
|
tests/test_oracle_apikey_api.py
|
|
255
|
+
tests/test_oracle_c3_bridge.py
|
|
256
|
+
tests/test_oracle_chat_engine.py
|
|
234
257
|
tests/test_oracle_discovery_api.py
|
|
258
|
+
tests/test_oracle_local_auth.py
|
|
259
|
+
tests/test_oracle_ollama_bridge.py
|
|
260
|
+
tests/test_oracle_scanner_cache.py
|
|
235
261
|
tests/test_oracle_security_fixes.py
|
|
262
|
+
tests/test_oracle_subproject_awareness.py
|
|
263
|
+
tests/test_oracle_ui_bundle.py
|
|
236
264
|
tests/test_output_filter.py
|
|
237
265
|
tests/test_permissions.py
|
|
238
266
|
tests/test_pm_api.py
|
|
@@ -242,6 +270,7 @@ tests/test_project_tool.py
|
|
|
242
270
|
tests/test_read_coercion.py
|
|
243
271
|
tests/test_response_boilerplate.py
|
|
244
272
|
tests/test_retention.py
|
|
273
|
+
tests/test_review_digest.py
|
|
245
274
|
tests/test_service_durability.py
|
|
246
275
|
tests/test_session_benchmark.py
|
|
247
276
|
tests/test_session_budget.py
|
|
@@ -18,10 +18,18 @@ DEFAULTS = {
|
|
|
18
18
|
"mcp_port": 3332, # discovery MCP transport port (loopback)
|
|
19
19
|
"ollama_base_url": "https://ollama.com",
|
|
20
20
|
"ollama_api_key": "",
|
|
21
|
+
"llm_cache_ttl_sec": 86400, # disk cache TTL for generate() responses
|
|
21
22
|
"model": "gemma4:31b-cloud",
|
|
22
23
|
"hub_url": "http://localhost:3330",
|
|
24
|
+
"scanner_ttl_seconds": 20,
|
|
23
25
|
"review_interval_seconds": 1800,
|
|
24
26
|
"review_enabled": True,
|
|
27
|
+
# ── Scheduled activity digest (runs inside the review loop) ──
|
|
28
|
+
"digest_enabled": False, # off = current behavior (on-demand only)
|
|
29
|
+
"digest_interval_seconds": 86400, # daily cadence once enabled
|
|
30
|
+
"digest_narrate": False, # LLM prose costs a cloud call; opt-in
|
|
31
|
+
"digest_notify_file": "", # "" = disabled; else JSONL sink path
|
|
32
|
+
"digest_retention_days": 14, # prune stored digests
|
|
25
33
|
"auto_open_browser": True,
|
|
26
34
|
"theme": "dark",
|
|
27
35
|
"max_facts_per_analysis": 100,
|
|
@@ -39,6 +47,7 @@ DEFAULTS = {
|
|
|
39
47
|
"description": "Expert in system architecture, design patterns, and cross-project structure. Best for high-level analysis.",
|
|
40
48
|
"system_prompt": "You are the Architect. Focus on structural integrity, design patterns, and the big picture. Provide high-level recommendations before diving into code.",
|
|
41
49
|
"model": "gemma4:31b-cloud",
|
|
50
|
+
"backend": "ollama",
|
|
42
51
|
"active": True
|
|
43
52
|
},
|
|
44
53
|
{
|
|
@@ -47,6 +56,7 @@ DEFAULTS = {
|
|
|
47
56
|
"description": "Specializes in deep code analysis, bug hunting, and tracing execution paths.",
|
|
48
57
|
"system_prompt": "You are the Code Explorer. Be incredibly precise, cite specific lines of code, and focus on the technical implementation details. Trace logic thoroughly.",
|
|
49
58
|
"model": "gemma4:31b-cloud",
|
|
59
|
+
"backend": "ollama",
|
|
50
60
|
"active": True
|
|
51
61
|
},
|
|
52
62
|
{
|
|
@@ -55,6 +65,7 @@ DEFAULTS = {
|
|
|
55
65
|
"description": "Focuses on analyzing project memory, facts, and insights.",
|
|
56
66
|
"system_prompt": "You are the Memory Analyst. Rely heavily on memory tools and facts to spot trends. Connect current issues to past context.",
|
|
57
67
|
"model": "gemma4:31b-cloud",
|
|
68
|
+
"backend": "ollama",
|
|
58
69
|
"active": True
|
|
59
70
|
}
|
|
60
71
|
],
|
|
@@ -991,6 +991,7 @@
|
|
|
991
991
|
<button class="btn btn-primary btn-sm" id="btnLoadActivity" onclick="loadActivity()">Refresh</button>
|
|
992
992
|
</div>
|
|
993
993
|
</div>
|
|
994
|
+
<div id="actScheduled" style="display:none;font-size:11px;color:var(--text2);margin-bottom:10px"></div>
|
|
994
995
|
<div id="actSummary" style="display:flex;gap:10px;flex-wrap:wrap;margin-bottom:14px"></div>
|
|
995
996
|
<div id="actNarrative" class="card" style="display:none;margin-bottom:14px"></div>
|
|
996
997
|
<div id="actProjects"></div>
|
|
@@ -1104,6 +1105,16 @@
|
|
|
1104
1105
|
<label>Review Interval (minutes)</label>
|
|
1105
1106
|
<input id="cfgInterval" type="number" min="1" value="30">
|
|
1106
1107
|
</div>
|
|
1108
|
+
<div class="field">
|
|
1109
|
+
<label style="display:flex;align-items:center;gap:8px">
|
|
1110
|
+
<input type="checkbox" id="cfgDigestEnabled" style="width:auto"> Scheduled activity digest
|
|
1111
|
+
</label>
|
|
1112
|
+
<p style="font-size:11px;color:var(--text2);margin-top:4px">Emit a cross-project digest from the review loop (Activity tab shows the latest).</p>
|
|
1113
|
+
</div>
|
|
1114
|
+
<div class="field">
|
|
1115
|
+
<label>Digest Interval (hours)</label>
|
|
1116
|
+
<input id="cfgDigestInterval" type="number" min="1" value="24">
|
|
1117
|
+
</div>
|
|
1107
1118
|
<div style="display:flex;gap:8px;margin-top:16px">
|
|
1108
1119
|
<button class="btn btn-primary" onclick="saveSettings()">Save</button>
|
|
1109
1120
|
<button class="btn btn-ghost" onclick="testConnection()">Test Connection</button>
|
|
@@ -1172,6 +1183,17 @@
|
|
|
1172
1183
|
<label>Model</label>
|
|
1173
1184
|
<input id="agentModel" type="text" placeholder="e.g. gemma4:31b-cloud">
|
|
1174
1185
|
</div>
|
|
1186
|
+
<div class="field">
|
|
1187
|
+
<label>Backend</label>
|
|
1188
|
+
<select id="agentBackend" style="width:100%;padding:8px;font-size:12px;background:var(--bg3);border:1px solid var(--border);border-radius:6px;color:var(--text)">
|
|
1189
|
+
<option value="ollama">Ollama (chat tool loop)</option>
|
|
1190
|
+
<option value="codex">Codex CLI (read-only, needs project)</option>
|
|
1191
|
+
<option value="gemini">Gemini CLI (read-only, needs project)</option>
|
|
1192
|
+
<option value="claude">Claude CLI (read-only, needs project)</option>
|
|
1193
|
+
<option value="auto">Auto cascade (read-only, needs project)</option>
|
|
1194
|
+
</select>
|
|
1195
|
+
<p style="font-size:11px;color:var(--text2);margin-top:4px">CLI backends run c3_delegate inside a registered project; the model field applies to Ollama only.</p>
|
|
1196
|
+
</div>
|
|
1175
1197
|
<div class="field" style="display:flex;align-items:center;gap:8px">
|
|
1176
1198
|
<input id="agentActive" type="checkbox" style="width:auto">
|
|
1177
1199
|
<label style="margin:0;cursor:pointer" for="agentActive">Active</label>
|
|
@@ -1927,7 +1949,23 @@ async function dismissInsight(id) {
|
|
|
1927
1949
|
// ═══════════════════════════════════════════════════════════
|
|
1928
1950
|
// ── Activity Digest ──
|
|
1929
1951
|
// ═══════════════════════════════════════════════════════════
|
|
1952
|
+
async function loadScheduledDigestBanner() {
|
|
1953
|
+
const el = document.getElementById('actScheduled');
|
|
1954
|
+
if (!el) return;
|
|
1955
|
+
try {
|
|
1956
|
+
const latest = await api('/api/activity/digest/latest');
|
|
1957
|
+
if (latest && latest.generated_at) {
|
|
1958
|
+
el.style.display = '';
|
|
1959
|
+
el.textContent = 'Last scheduled digest: ' +
|
|
1960
|
+
latest.generated_at.replace('T', ' ').slice(0, 19) + ' UTC';
|
|
1961
|
+
} else {
|
|
1962
|
+
el.style.display = 'none';
|
|
1963
|
+
}
|
|
1964
|
+
} catch { el.style.display = 'none'; }
|
|
1965
|
+
}
|
|
1966
|
+
|
|
1930
1967
|
async function loadActivity() {
|
|
1968
|
+
loadScheduledDigestBanner();
|
|
1931
1969
|
const dateEl = document.getElementById('actDate');
|
|
1932
1970
|
if (dateEl && !dateEl.value) dateEl.value = new Date().toISOString().slice(0, 10);
|
|
1933
1971
|
const date = dateEl ? dateEl.value : '';
|
|
@@ -2076,6 +2114,8 @@ async function loadSettings() {
|
|
|
2076
2114
|
keyCheck.parentElement.style.display = hasKey ? '' : 'none';
|
|
2077
2115
|
document.getElementById('cfgHubUrl').value = cfg.hub_url || '';
|
|
2078
2116
|
document.getElementById('cfgInterval').value = Math.round((cfg.review_interval_seconds || 1800) / 60);
|
|
2117
|
+
document.getElementById('cfgDigestEnabled').checked = !!cfg.digest_enabled;
|
|
2118
|
+
document.getElementById('cfgDigestInterval').value = Math.round((cfg.digest_interval_seconds || 86400) / 3600);
|
|
2079
2119
|
applyTheme(cfg.theme || 'dark');
|
|
2080
2120
|
// Hub link
|
|
2081
2121
|
const hubUrl = cfg.hub_url || 'http://localhost:3330';
|
|
@@ -2122,6 +2162,8 @@ async function saveSettings() {
|
|
|
2122
2162
|
ollama_base_url: document.getElementById('cfgOllamaUrl').value,
|
|
2123
2163
|
hub_url: document.getElementById('cfgHubUrl').value,
|
|
2124
2164
|
review_interval_seconds: parseInt(document.getElementById('cfgInterval').value) * 60,
|
|
2165
|
+
digest_enabled: document.getElementById('cfgDigestEnabled').checked,
|
|
2166
|
+
digest_interval_seconds: parseInt(document.getElementById('cfgDigestInterval').value) * 3600,
|
|
2125
2167
|
agents: window.oracleAgents
|
|
2126
2168
|
};
|
|
2127
2169
|
if (apiKeyVal) cfg.ollama_api_key = apiKeyVal;
|
|
@@ -4040,7 +4082,7 @@ function renderAgents() {
|
|
|
4040
4082
|
<div style="flex:1;min-width:0;margin-right:16px">
|
|
4041
4083
|
<div style="font-weight:600;font-size:14px;margin-bottom:4px;display:flex;align-items:center;gap:8px">
|
|
4042
4084
|
${esc(a.name)}
|
|
4043
|
-
<span style="font-size:10px;font-family:monospace;background:var(--bg3);padding:2px 6px;border-radius:4px;color:var(--text2)">${esc(a.model)}</span>
|
|
4085
|
+
<span style="font-size:10px;font-family:monospace;background:var(--bg3);padding:2px 6px;border-radius:4px;color:var(--text2)">${esc(a.backend && a.backend !== 'ollama' ? a.backend : a.model)}</span>
|
|
4044
4086
|
</div>
|
|
4045
4087
|
<div style="font-size:12px;color:var(--text2);white-space:nowrap;overflow:hidden;text-overflow:ellipsis" title="${esc(a.description)}">${esc(a.description)}</div>
|
|
4046
4088
|
</div>
|
|
@@ -4071,6 +4113,7 @@ function openAgentModal(id = null) {
|
|
|
4071
4113
|
descInput.value = a.description || '';
|
|
4072
4114
|
promptInput.value = a.system_prompt || '';
|
|
4073
4115
|
modelInput.value = a.model || '';
|
|
4116
|
+
document.getElementById('agentBackend').value = a.backend || 'ollama';
|
|
4074
4117
|
activeInput.checked = a.active !== false;
|
|
4075
4118
|
} else {
|
|
4076
4119
|
title.textContent = 'Add Custom Agent';
|
|
@@ -4079,6 +4122,7 @@ function openAgentModal(id = null) {
|
|
|
4079
4122
|
descInput.value = '';
|
|
4080
4123
|
promptInput.value = '';
|
|
4081
4124
|
modelInput.value = window.oracleConfig.model || 'gemma4:31b-cloud';
|
|
4125
|
+
document.getElementById('agentBackend').value = 'ollama';
|
|
4082
4126
|
activeInput.checked = true;
|
|
4083
4127
|
}
|
|
4084
4128
|
|
|
@@ -4100,6 +4144,7 @@ function saveAgent() {
|
|
|
4100
4144
|
description: document.getElementById('agentDesc').value.trim(),
|
|
4101
4145
|
system_prompt: document.getElementById('agentPrompt').value.trim(),
|
|
4102
4146
|
model: document.getElementById('agentModel').value.trim(),
|
|
4147
|
+
backend: document.getElementById('agentBackend').value,
|
|
4103
4148
|
active: document.getElementById('agentActive').checked
|
|
4104
4149
|
};
|
|
4105
4150
|
|
|
@@ -20,7 +20,7 @@ from flask import Flask, Response, jsonify, request, send_from_directory # noqa
|
|
|
20
20
|
|
|
21
21
|
from oracle.config import ORACLE_DIR, load_config, save_config # noqa: E402
|
|
22
22
|
from oracle.mcp_oracle import mcp_url, start_mcp_thread # noqa: E402
|
|
23
|
-
from oracle.services import api_auth # noqa: E402
|
|
23
|
+
from oracle.services import api_auth, local_session # noqa: E402
|
|
24
24
|
from oracle.services.activity_reporter import ActivityReporter # noqa: E402
|
|
25
25
|
from oracle.services.api_auth import extract_bearer # noqa: E402
|
|
26
26
|
from oracle.services.api_auth import verify as verify_api_key # noqa: E402
|
|
@@ -68,6 +68,7 @@ def _init_services():
|
|
|
68
68
|
base_url=_cfg.get("ollama_base_url", "https://ollama.com"),
|
|
69
69
|
model=_cfg.get("model", "gemma4:31b-cloud"),
|
|
70
70
|
api_key=_cfg.get("ollama_api_key", ""),
|
|
71
|
+
cache_ttl_sec=int(_cfg.get("llm_cache_ttl_sec", 86400)),
|
|
71
72
|
)
|
|
72
73
|
# Verify model works on startup (background thread to avoid blocking)
|
|
73
74
|
def _verify():
|
|
@@ -80,7 +81,10 @@ def _init_services():
|
|
|
80
81
|
_model_verified = False
|
|
81
82
|
logging.getLogger("oracle").warning("Ollama unreachable — model not verified")
|
|
82
83
|
threading.Thread(target=_verify, daemon=True, name="oracle-model-verify").start()
|
|
83
|
-
_scanner = ProjectScanner(
|
|
84
|
+
_scanner = ProjectScanner(
|
|
85
|
+
hub_url=_cfg.get("hub_url", "http://localhost:3330"),
|
|
86
|
+
ttl=float(_cfg.get("scanner_ttl_seconds", 20)),
|
|
87
|
+
)
|
|
84
88
|
_reader = MemoryReader()
|
|
85
89
|
_checker = HealthChecker(_reader)
|
|
86
90
|
_writer = MemoryWriter()
|
|
@@ -89,6 +93,8 @@ def _init_services():
|
|
|
89
93
|
_chat_store = ChatStore()
|
|
90
94
|
_c3_bridge = C3Bridge(scanner=_scanner)
|
|
91
95
|
_federated = FederatedGraph(reader=_reader, cross_memory=_cross_memory, ollama_bridge=_bridge)
|
|
96
|
+
# Reporter before ReviewAgent: the review loop emits the scheduled digest.
|
|
97
|
+
_activity_reporter = ActivityReporter(scanner=_scanner, ollama_bridge=_bridge)
|
|
92
98
|
_agent = ReviewAgent(
|
|
93
99
|
scanner=_scanner,
|
|
94
100
|
reader=_reader,
|
|
@@ -98,8 +104,8 @@ def _init_services():
|
|
|
98
104
|
writer=_writer,
|
|
99
105
|
interval=int(_cfg.get("review_interval_seconds", 1800)),
|
|
100
106
|
federated_graph=_federated,
|
|
107
|
+
activity_reporter=_activity_reporter,
|
|
101
108
|
)
|
|
102
|
-
_activity_reporter = ActivityReporter(scanner=_scanner, ollama_bridge=_bridge)
|
|
103
109
|
_chat_engine = ChatEngine(
|
|
104
110
|
bridge=_bridge,
|
|
105
111
|
reader=_reader,
|
|
@@ -122,9 +128,10 @@ def _init_services():
|
|
|
122
128
|
# ── CORS ──────────────────────────────────────────────────
|
|
123
129
|
# Localhost security guard + scoped CORS (replaces the previous wildcard CORS).
|
|
124
130
|
# Host-header allowlist + Origin/Referer CSRF guard. Bearer auth on
|
|
125
|
-
# /api/discovery/* (see _discovery_auth_guard below)
|
|
126
|
-
#
|
|
127
|
-
#
|
|
131
|
+
# /api/discovery/* (see _discovery_auth_guard below) and the local write gate
|
|
132
|
+
# (_local_write_guard: session cookie or Bearer on every other mutating
|
|
133
|
+
# /api/* call) still apply on top; this guard blocks cross-origin browsers,
|
|
134
|
+
# the write gate blocks unauthenticated local processes.
|
|
128
135
|
from core.web_security import (
|
|
129
136
|
allowed_hostnames as _allowed_hostnames,
|
|
130
137
|
)
|
|
@@ -155,10 +162,99 @@ def _discovery_auth_guard():
|
|
|
155
162
|
return None
|
|
156
163
|
|
|
157
164
|
|
|
165
|
+
# ── Local write gate ──────────────────────────────────────
|
|
166
|
+
@app.before_request
|
|
167
|
+
def _local_write_guard():
|
|
168
|
+
"""Auth gate for mutating local API calls (everything except Discovery).
|
|
169
|
+
|
|
170
|
+
Requires either the per-boot dashboard session cookie (issued on ``GET /``
|
|
171
|
+
to loopback browsers) or the Discovery Bearer token. Default-deny: any
|
|
172
|
+
future mutating ``/api/*`` endpoint is covered automatically. Closes the
|
|
173
|
+
rotate-then-read kill chain — previously any local process could POST
|
|
174
|
+
/api/apikey/rotate unauthenticated and read the fresh token, defeating
|
|
175
|
+
the Bearer gates on /api/config and /api/discovery/*.
|
|
176
|
+
"""
|
|
177
|
+
path = request.path or ""
|
|
178
|
+
if not path.startswith("/api/") or path.startswith("/api/discovery"):
|
|
179
|
+
return None
|
|
180
|
+
if request.method in ("GET", "HEAD", "OPTIONS"):
|
|
181
|
+
return None
|
|
182
|
+
if verify_api_key(extract_bearer(request.headers.get("Authorization"))):
|
|
183
|
+
return None
|
|
184
|
+
if local_session.verify(request.cookies.get(local_session.COOKIE_NAME)):
|
|
185
|
+
return None
|
|
186
|
+
return jsonify({"error": "unauthorized"}), 401
|
|
187
|
+
|
|
188
|
+
|
|
158
189
|
# ── Static ────────────────────────────────────────────────
|
|
190
|
+
|
|
191
|
+
# JS load order for the concatenated Oracle UI build (mirrors cli/hub_server.py).
|
|
192
|
+
# One shared script scope: function declarations hoist across files, and
|
|
193
|
+
# app.js (the init IIFE) must stay LAST.
|
|
194
|
+
_ORACLE_JS_FILES = [
|
|
195
|
+
"ui/core.js",
|
|
196
|
+
"ui/busy.js",
|
|
197
|
+
"ui/theme_tabs.js",
|
|
198
|
+
"ui/crossgraph.js",
|
|
199
|
+
"ui/header.js",
|
|
200
|
+
"ui/projects.js",
|
|
201
|
+
"ui/insights.js",
|
|
202
|
+
"ui/activity.js",
|
|
203
|
+
"ui/suggestions.js",
|
|
204
|
+
"ui/settings.js",
|
|
205
|
+
"ui/agents.js",
|
|
206
|
+
"ui/chat/markdown.js",
|
|
207
|
+
"ui/chat/conversations.js",
|
|
208
|
+
"ui/chat/stream_renderer.js",
|
|
209
|
+
"ui/chat/toolbar.js",
|
|
210
|
+
"ui/chat/input.js",
|
|
211
|
+
"ui/chat/send.js",
|
|
212
|
+
"ui/app.js",
|
|
213
|
+
]
|
|
214
|
+
|
|
215
|
+
|
|
216
|
+
def _build_oracle_html() -> str:
|
|
217
|
+
"""Concatenate oracle_ui.html shell + all JS module files into one response."""
|
|
218
|
+
oracle_dir = Path(__file__).parent
|
|
219
|
+
shell_path = oracle_dir / "oracle_ui.html"
|
|
220
|
+
if not shell_path.exists():
|
|
221
|
+
return "<h1>Oracle UI not found.</h1>"
|
|
222
|
+
|
|
223
|
+
shell = shell_path.read_text(encoding="utf-8")
|
|
224
|
+
|
|
225
|
+
js_parts = []
|
|
226
|
+
for rel in _ORACLE_JS_FILES:
|
|
227
|
+
js_path = oracle_dir / rel
|
|
228
|
+
if js_path.exists():
|
|
229
|
+
js_parts.append(f"// ═══ {rel} ═══\n" + js_path.read_text(encoding="utf-8"))
|
|
230
|
+
|
|
231
|
+
return shell.replace("/* __C3_ORACLE_SCRIPTS__ */", "\n\n".join(js_parts))
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
# Cache the built HTML (built on first request; cleared on server restart).
|
|
235
|
+
_oracle_html_cache: str | None = None
|
|
236
|
+
|
|
237
|
+
|
|
159
238
|
@app.route("/")
|
|
160
239
|
def index():
|
|
161
|
-
|
|
240
|
+
global _oracle_html_cache
|
|
241
|
+
if _oracle_html_cache is None:
|
|
242
|
+
_oracle_html_cache = _build_oracle_html()
|
|
243
|
+
resp = Response(_oracle_html_cache, mimetype="text/html")
|
|
244
|
+
# Issue the dashboard session cookie only to loopback browsers; remote
|
|
245
|
+
# viewers (LAN bind) can read GET dashboards but cannot mutate.
|
|
246
|
+
if local_session.is_loopback(request.remote_addr):
|
|
247
|
+
local_session.attach_cookie(resp)
|
|
248
|
+
return resp
|
|
249
|
+
|
|
250
|
+
|
|
251
|
+
@app.route("/legacy")
|
|
252
|
+
def index_legacy():
|
|
253
|
+
"""Frozen pre-bundle Oracle UI — escape hatch for one release, then removed."""
|
|
254
|
+
resp = send_from_directory(os.path.dirname(__file__), "oracle.html")
|
|
255
|
+
if local_session.is_loopback(request.remote_addr):
|
|
256
|
+
local_session.attach_cookie(resp)
|
|
257
|
+
return resp
|
|
162
258
|
|
|
163
259
|
|
|
164
260
|
# ── Health ────────────────────────────────────────────────
|
|
@@ -206,11 +302,9 @@ _CONFIG_SETTABLE_KEYS = frozenset(_CONFIG_DEFAULTS.keys())
|
|
|
206
302
|
@app.route("/api/config", methods=["POST"])
|
|
207
303
|
def api_config_set():
|
|
208
304
|
global _cfg
|
|
209
|
-
#
|
|
210
|
-
# repoint ollama_base_url, so it
|
|
211
|
-
|
|
212
|
-
if not verify_api_key(token):
|
|
213
|
-
return jsonify({"error": "unauthorized"}), 401
|
|
305
|
+
# Auth is enforced by _local_write_guard (session cookie or Bearer): this
|
|
306
|
+
# endpoint can disable Discovery auth or repoint ollama_base_url, so it
|
|
307
|
+
# must never be reachable unauthenticated.
|
|
214
308
|
body = request.get_json(silent=True) or {}
|
|
215
309
|
if not isinstance(body, dict):
|
|
216
310
|
return jsonify({"error": "body must be a JSON object"}), 400
|
|
@@ -258,7 +352,8 @@ def api_projects():
|
|
|
258
352
|
|
|
259
353
|
@app.route("/api/projects/scan", methods=["POST"])
|
|
260
354
|
def api_projects_scan():
|
|
261
|
-
|
|
355
|
+
# Explicit Scan action bypasses the scanner's TTL cache.
|
|
356
|
+
projects = _scanner.discover(force=True) if _scanner else []
|
|
262
357
|
return jsonify({"scanned": len(projects), "projects": projects})
|
|
263
358
|
|
|
264
359
|
|
|
@@ -635,6 +730,23 @@ def api_chat_conversation_state(conv_id):
|
|
|
635
730
|
|
|
636
731
|
|
|
637
732
|
# ── Activity digest (Oracle UI) ───────────────────────────
|
|
733
|
+
@app.route("/api/activity/digest/latest", methods=["GET"])
|
|
734
|
+
def api_activity_digest_latest():
|
|
735
|
+
"""Most recent SCHEDULED digest (written by the review loop), or null.
|
|
736
|
+
|
|
737
|
+
On-demand digests via /api/activity/digest are not persisted here; this
|
|
738
|
+
serves ~/.c3/oracle/activity_digests/latest.json.
|
|
739
|
+
"""
|
|
740
|
+
latest = ORACLE_DIR / "activity_digests" / "latest.json"
|
|
741
|
+
try:
|
|
742
|
+
if latest.is_file():
|
|
743
|
+
return Response(latest.read_text(encoding="utf-8"),
|
|
744
|
+
mimetype="application/json")
|
|
745
|
+
except Exception as e:
|
|
746
|
+
return jsonify({"error": str(e)}), 500
|
|
747
|
+
return jsonify({"digest": None, "generated_at": None})
|
|
748
|
+
|
|
749
|
+
|
|
638
750
|
@app.route("/api/activity/digest", methods=["GET"])
|
|
639
751
|
def api_activity_digest():
|
|
640
752
|
"""Cross-project activity digest for the Oracle UI.
|
|
@@ -740,7 +852,7 @@ def api_discovery_mcp_info():
|
|
|
740
852
|
})
|
|
741
853
|
|
|
742
854
|
|
|
743
|
-
# ── Discovery API key management (
|
|
855
|
+
# ── Discovery API key management (mutations gated by _local_write_guard) ──
|
|
744
856
|
def _apikey_status(reveal: bool = False) -> dict:
|
|
745
857
|
"""Status payload for the Discovery API token + connection info.
|
|
746
858
|
|
|
@@ -786,12 +898,14 @@ def _apikey_status(reveal: bool = False) -> dict:
|
|
|
786
898
|
def api_apikey_get():
|
|
787
899
|
"""Return Discovery API token status + connection info.
|
|
788
900
|
|
|
789
|
-
The unmasked token is only included when the caller presents a valid
|
|
790
|
-
token
|
|
791
|
-
HTTP unauthenticated).
|
|
901
|
+
The unmasked token is only included when the caller presents a valid
|
|
902
|
+
Bearer token or the dashboard session cookie; otherwise only the masked
|
|
903
|
+
form is returned (never the raw key over HTTP unauthenticated).
|
|
792
904
|
"""
|
|
793
905
|
try:
|
|
794
|
-
reveal = verify_api_key(
|
|
906
|
+
reveal = verify_api_key(
|
|
907
|
+
extract_bearer(request.headers.get("Authorization"))
|
|
908
|
+
) or local_session.verify(request.cookies.get(local_session.COOKIE_NAME))
|
|
795
909
|
return jsonify(_apikey_status(reveal=reveal))
|
|
796
910
|
except Exception as e:
|
|
797
911
|
return jsonify({"error": str(e)}), 500
|