code-context-control 2.46.1__tar.gz → 2.49.1__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.1/code_context_control.egg-info → code_context_control-2.49.1}/PKG-INFO +1 -1
- {code_context_control-2.46.1 → code_context_control-2.49.1}/cli/c3.py +11 -3
- {code_context_control-2.46.1 → code_context_control-2.49.1}/cli/commands/parser.py +10 -1
- {code_context_control-2.46.1 → code_context_control-2.49.1/code_context_control.egg-info}/PKG-INFO +1 -1
- {code_context_control-2.46.1 → code_context_control-2.49.1}/code_context_control.egg-info/SOURCES.txt +29 -1
- {code_context_control-2.46.1 → code_context_control-2.49.1}/oracle/config.py +12 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/oracle/oracle_server.py +125 -20
- code_context_control-2.49.1/oracle/oracle_ui.html +1217 -0
- code_context_control-2.49.1/oracle/services/c3_bridge.py +372 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/oracle/services/chat_engine.py +453 -141
- {code_context_control-2.46.1 → code_context_control-2.49.1}/oracle/services/federated_graph.py +52 -2
- code_context_control-2.49.1/oracle/services/local_session.py +54 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/oracle/services/ollama_bridge.py +87 -7
- {code_context_control-2.46.1 → code_context_control-2.49.1}/oracle/services/project_scanner.py +60 -6
- {code_context_control-2.46.1 → code_context_control-2.49.1}/oracle/services/review_agent.py +84 -1
- {code_context_control-2.46.1 → code_context_control-2.49.1}/oracle/services/tool_registry.py +82 -3
- code_context_control-2.49.1/oracle/ui/activity.js +101 -0
- code_context_control-2.49.1/oracle/ui/agents.js +108 -0
- code_context_control-2.49.1/oracle/ui/app.js +11 -0
- code_context_control-2.49.1/oracle/ui/busy.js +102 -0
- code_context_control-2.49.1/oracle/ui/chat/conversations.js +153 -0
- code_context_control-2.49.1/oracle/ui/chat/input.js +284 -0
- code_context_control-2.49.1/oracle/ui/chat/markdown.js +33 -0
- code_context_control-2.49.1/oracle/ui/chat/send.js +281 -0
- code_context_control-2.49.1/oracle/ui/chat/stream_renderer.js +767 -0
- code_context_control-2.49.1/oracle/ui/chat/toolbar.js +270 -0
- code_context_control-2.49.1/oracle/ui/core.js +60 -0
- code_context_control-2.49.1/oracle/ui/crossgraph.js +184 -0
- code_context_control-2.49.1/oracle/ui/header.js +75 -0
- code_context_control-2.49.1/oracle/ui/insights.js +52 -0
- code_context_control-2.49.1/oracle/ui/projects.js +245 -0
- code_context_control-2.49.1/oracle/ui/settings.js +186 -0
- code_context_control-2.49.1/oracle/ui/suggestions.js +47 -0
- code_context_control-2.49.1/oracle/ui/theme_tabs.js +68 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/pyproject.toml +5 -1
- {code_context_control-2.46.1 → code_context_control-2.49.1}/services/project_runtime.py +16 -3
- code_context_control-2.49.1/tests/test_c3_bridge_project_artifacts.py +153 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/tests/test_federated_graph.py +83 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/tests/test_oracle_apikey_api.py +8 -2
- code_context_control-2.49.1/tests/test_oracle_c3_bridge.py +174 -0
- code_context_control-2.49.1/tests/test_oracle_chat_engine.py +551 -0
- code_context_control-2.49.1/tests/test_oracle_local_auth.py +228 -0
- code_context_control-2.49.1/tests/test_oracle_ollama_bridge.py +203 -0
- code_context_control-2.49.1/tests/test_oracle_scanner_cache.py +94 -0
- code_context_control-2.49.1/tests/test_oracle_subproject_awareness.py +131 -0
- code_context_control-2.49.1/tests/test_oracle_ui_bundle.py +86 -0
- code_context_control-2.49.1/tests/test_review_digest.py +184 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/tests/test_tool_registry.py +32 -0
- code_context_control-2.46.1/oracle/oracle.html +0 -4136
- code_context_control-2.46.1/oracle/services/c3_bridge.py +0 -237
- {code_context_control-2.46.1 → code_context_control-2.49.1}/LICENSE +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/README.md +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/cli/__init__.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/cli/_hook_utils.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/cli/commands/__init__.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/cli/commands/common.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/cli/docs.html +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/cli/edits.html +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/cli/guide/bitbucket.html +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/cli/guide/getting-started.html +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/cli/guide/index.html +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/cli/guide/oracle.html +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/cli/guide/shared.css +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/cli/guide/tools.html +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/cli/guide/workflow.html +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/cli/hook_artifact.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/cli/hook_auto_snapshot.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/cli/hook_c3_signal.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/cli/hook_c3read.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/cli/hook_dispatch.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/cli/hook_edit_ledger.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/cli/hook_edit_unlock.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/cli/hook_filter.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/cli/hook_ghost_files.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/cli/hook_pretool_enforce.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/cli/hook_read.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/cli/hook_session_stats.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/cli/hook_terse_advisor.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/cli/hub.html +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/cli/hub_server.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/cli/hub_ui/app.js +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/cli/hub_ui/components/add_project.js +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/cli/hub_ui/components/config_editor.js +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/cli/hub_ui/components/drill_artifacts.js +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/cli/hub_ui/components/drill_health.js +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/cli/hub_ui/components/drill_panel.js +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/cli/hub_ui/components/drill_tasks.js +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/cli/hub_ui/components/drill_views.js +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/cli/hub_ui/components/global_search.js +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/cli/hub_ui/components/mcp_manager.js +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/cli/hub_ui/components/modals.js +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/cli/hub_ui/components/project_card.js +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/cli/hub_ui/components/project_tree.js +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/cli/hub_ui/components/session_drawer.js +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/cli/hub_ui/components/settings_modal.js +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/cli/hub_ui/components/sidebar.js +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/cli/hub_ui/components/summary_bar.js +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/cli/hub_ui/components/task_board.js +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/cli/hub_ui/components/toasts.js +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/cli/hub_ui/components/topbar.js +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/cli/hub_ui/state.js +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/cli/hub_ui.html +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/cli/mcp_proxy.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/cli/mcp_server.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/cli/server.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/cli/tools/__init__.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/cli/tools/_helpers.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/cli/tools/agent.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/cli/tools/artifacts.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/cli/tools/bitbucket.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/cli/tools/compress.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/cli/tools/delegate.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/cli/tools/edit.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/cli/tools/edits.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/cli/tools/federate.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/cli/tools/filter.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/cli/tools/impact.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/cli/tools/memory.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/cli/tools/project.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/cli/tools/read.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/cli/tools/search.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/cli/tools/session.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/cli/tools/shell.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/cli/tools/status.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/cli/tools/tasks.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/cli/tools/validate.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/cli/ui/api.js +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/cli/ui/app.js +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/cli/ui/components/bitbucket.js +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/cli/ui/components/chat.js +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/cli/ui/components/dashboard.js +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/cli/ui/components/edits.js +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/cli/ui/components/instructions.js +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/cli/ui/components/memory.js +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/cli/ui/components/sessions.js +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/cli/ui/components/settings.js +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/cli/ui/components/sidebar.js +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/cli/ui/components/tasks.js +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/cli/ui/icons.js +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/cli/ui/pm_shared.js +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/cli/ui/shared.js +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/cli/ui/theme.js +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/cli/ui.html +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/cli/ui_legacy.html +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/cli/ui_nano.html +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/code_context_control.egg-info/dependency_links.txt +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/code_context_control.egg-info/entry_points.txt +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/code_context_control.egg-info/requires.txt +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/code_context_control.egg-info/top_level.txt +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/core/__init__.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/core/config.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/core/ide.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/core/mcp_toml.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/core/web_security.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/oracle/__init__.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/oracle/mcp_oracle.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/oracle/services/__init__.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/oracle/services/activity_reporter.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/oracle/services/api_auth.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/oracle/services/chat_store.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/oracle/services/cross_memory.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/oracle/services/health_checker.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/oracle/services/insight_engine.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/oracle/services/memory_reader.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/oracle/services/memory_writer.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/oracle/services/tool_executor.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/services/__init__.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/services/activity_log.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/services/agent_base.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/services/agents.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/services/artifact_defs.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/services/artifact_store.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/services/auto_memory.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/services/bench/__init__.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/services/bench/external/__init__.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/services/bench/external/aider_polyglot.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/services/bench/external/swe_bench.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/services/benchmark_dashboard.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/services/bitbucket_client.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/services/bitbucket_credentials.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/services/circuit_breaker.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/services/claude_md.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/services/compressor.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/services/context_snapshot.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/services/conversation_store.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/services/doc_index.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/services/e2e_benchmark.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/services/e2e_evaluator.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/services/e2e_tasks.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/services/edit_ledger.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/services/embedding_index.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/services/error_reporting.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/services/file_memory.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/services/git_context.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/services/hub_service.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/services/indexer.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/services/memory.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/services/memory_consolidator.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/services/memory_graph.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/services/memory_grounder.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/services/memory_scorer.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/services/metrics.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/services/notifications.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/services/ollama_client.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/services/output_filter.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/services/parser.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/services/project_manager.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/services/protocol.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/services/proxy_state.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/services/retention.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/services/retrieval_broker.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/services/router.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/services/runtime.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/services/session_benchmark.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/services/session_manager.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/services/session_preloader.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/services/subprojects.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/services/task_store.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/services/telemetry.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/services/text_index.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/services/tool_classifier.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/services/transcript_index.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/services/validation_cache.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/services/vector_store.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/services/watcher.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/services/win_subprocess.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/setup.cfg +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/tests/test_activity_reporter.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/tests/test_aider_polyglot.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/tests/test_artifact_store.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/tests/test_artifact_tool.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/tests/test_bitbucket_cli_smoke.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/tests/test_bitbucket_client.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/tests/test_bitbucket_config_fallback.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/tests/test_bitbucket_credentials.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/tests/test_bitbucket_tool.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/tests/test_c3_shell.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/tests/test_circuit_breaker.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/tests/test_claude_md_merge.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/tests/test_cli_smoke.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/tests/test_compressor_large_file.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/tests/test_delegate_cascade.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/tests/test_e2e_benchmark.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/tests/test_edit_ledger_hook.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/tests/test_edit_normalization.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/tests/test_enforcement_flip.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/tests/test_filter_backoff.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/tests/test_ghost_files.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/tests/test_ghost_generation.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/tests/test_git_branch_awareness.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/tests/test_hook_dispatch.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/tests/test_hook_pretool_enforce.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/tests/test_hook_smoke.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/tests/test_hook_state.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/tests/test_hub_inspect_api.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/tests/test_hub_server_smoke.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/tests/test_install_mcp_entrypoint.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/tests/test_lazy_store_init.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/tests/test_mcp_host_guard.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/tests/test_mcp_server_smoke.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/tests/test_mcp_toml.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/tests/test_memory_graph_api.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/tests/test_memory_system.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/tests/test_notification_dedup.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/tests/test_notification_discipline.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/tests/test_oracle_api_auth.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/tests/test_oracle_discovery_api.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/tests/test_oracle_security_fixes.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/tests/test_output_filter.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/tests/test_permissions.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/tests/test_pm_api.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/tests/test_project_manager.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/tests/test_project_manager_merge.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/tests/test_project_tool.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/tests/test_read_coercion.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/tests/test_response_boilerplate.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/tests/test_retention.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/tests/test_service_durability.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/tests/test_session_benchmark.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/tests/test_session_budget.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/tests/test_shell_robustness.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/tests/test_subproject_exclusion.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/tests/test_subproject_federation.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/tests/test_subprojects.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/tests/test_swe_bench.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/tests/test_task_store.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/tests/test_task_tool.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/tests/test_token_telemetry.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/tests/test_upgrade_and_version.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/tests/test_validate.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/tests/test_web_security.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/tests/test_windows_reliability.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/tui/__init__.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/tui/backend.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/tui/main.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/tui/screens/__init__.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/tui/screens/benchmark_view.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/tui/screens/claudemd_view.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/tui/screens/compress_view.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/tui/screens/index_view.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/tui/screens/init_view.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/tui/screens/mcp_view.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/tui/screens/optimize_view.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/tui/screens/pipe_view.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/tui/screens/projects_view.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/tui/screens/search_view.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/tui/screens/session_view.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/tui/screens/stats.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/tui/screens/ui_view.py +0 -0
- {code_context_control-2.46.1 → code_context_control-2.49.1}/tui/theme.tcss +0 -0
{code_context_control-2.46.1/code_context_control.egg-info → code_context_control-2.49.1}/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.1
|
|
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.1"
|
|
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",
|
{code_context_control-2.46.1 → code_context_control-2.49.1/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.1
|
|
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
|
|
@@ -110,8 +110,8 @@ core/web_security.py
|
|
|
110
110
|
oracle/__init__.py
|
|
111
111
|
oracle/config.py
|
|
112
112
|
oracle/mcp_oracle.py
|
|
113
|
-
oracle/oracle.html
|
|
114
113
|
oracle/oracle_server.py
|
|
114
|
+
oracle/oracle_ui.html
|
|
115
115
|
oracle/services/__init__.py
|
|
116
116
|
oracle/services/activity_reporter.py
|
|
117
117
|
oracle/services/api_auth.py
|
|
@@ -122,6 +122,7 @@ oracle/services/cross_memory.py
|
|
|
122
122
|
oracle/services/federated_graph.py
|
|
123
123
|
oracle/services/health_checker.py
|
|
124
124
|
oracle/services/insight_engine.py
|
|
125
|
+
oracle/services/local_session.py
|
|
125
126
|
oracle/services/memory_reader.py
|
|
126
127
|
oracle/services/memory_writer.py
|
|
127
128
|
oracle/services/ollama_bridge.py
|
|
@@ -129,6 +130,24 @@ oracle/services/project_scanner.py
|
|
|
129
130
|
oracle/services/review_agent.py
|
|
130
131
|
oracle/services/tool_executor.py
|
|
131
132
|
oracle/services/tool_registry.py
|
|
133
|
+
oracle/ui/activity.js
|
|
134
|
+
oracle/ui/agents.js
|
|
135
|
+
oracle/ui/app.js
|
|
136
|
+
oracle/ui/busy.js
|
|
137
|
+
oracle/ui/core.js
|
|
138
|
+
oracle/ui/crossgraph.js
|
|
139
|
+
oracle/ui/header.js
|
|
140
|
+
oracle/ui/insights.js
|
|
141
|
+
oracle/ui/projects.js
|
|
142
|
+
oracle/ui/settings.js
|
|
143
|
+
oracle/ui/suggestions.js
|
|
144
|
+
oracle/ui/theme_tabs.js
|
|
145
|
+
oracle/ui/chat/conversations.js
|
|
146
|
+
oracle/ui/chat/input.js
|
|
147
|
+
oracle/ui/chat/markdown.js
|
|
148
|
+
oracle/ui/chat/send.js
|
|
149
|
+
oracle/ui/chat/stream_renderer.js
|
|
150
|
+
oracle/ui/chat/toolbar.js
|
|
132
151
|
services/__init__.py
|
|
133
152
|
services/activity_log.py
|
|
134
153
|
services/agent_base.py
|
|
@@ -199,6 +218,7 @@ tests/test_bitbucket_client.py
|
|
|
199
218
|
tests/test_bitbucket_config_fallback.py
|
|
200
219
|
tests/test_bitbucket_credentials.py
|
|
201
220
|
tests/test_bitbucket_tool.py
|
|
221
|
+
tests/test_c3_bridge_project_artifacts.py
|
|
202
222
|
tests/test_c3_shell.py
|
|
203
223
|
tests/test_circuit_breaker.py
|
|
204
224
|
tests/test_claude_md_merge.py
|
|
@@ -231,8 +251,15 @@ tests/test_notification_dedup.py
|
|
|
231
251
|
tests/test_notification_discipline.py
|
|
232
252
|
tests/test_oracle_api_auth.py
|
|
233
253
|
tests/test_oracle_apikey_api.py
|
|
254
|
+
tests/test_oracle_c3_bridge.py
|
|
255
|
+
tests/test_oracle_chat_engine.py
|
|
234
256
|
tests/test_oracle_discovery_api.py
|
|
257
|
+
tests/test_oracle_local_auth.py
|
|
258
|
+
tests/test_oracle_ollama_bridge.py
|
|
259
|
+
tests/test_oracle_scanner_cache.py
|
|
235
260
|
tests/test_oracle_security_fixes.py
|
|
261
|
+
tests/test_oracle_subproject_awareness.py
|
|
262
|
+
tests/test_oracle_ui_bundle.py
|
|
236
263
|
tests/test_output_filter.py
|
|
237
264
|
tests/test_permissions.py
|
|
238
265
|
tests/test_pm_api.py
|
|
@@ -242,6 +269,7 @@ tests/test_project_tool.py
|
|
|
242
269
|
tests/test_read_coercion.py
|
|
243
270
|
tests/test_response_boilerplate.py
|
|
244
271
|
tests/test_retention.py
|
|
272
|
+
tests/test_review_digest.py
|
|
245
273
|
tests/test_service_durability.py
|
|
246
274
|
tests/test_session_benchmark.py
|
|
247
275
|
tests/test_session_budget.py
|
|
@@ -18,12 +18,21 @@ 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",
|
|
35
|
+
"ui_last_tab": "chat", # persisted UI preference (hub parity)
|
|
27
36
|
"max_facts_per_analysis": 100,
|
|
28
37
|
"insight_confidence_threshold": 0.5,
|
|
29
38
|
"log_level": "INFO",
|
|
@@ -39,6 +48,7 @@ DEFAULTS = {
|
|
|
39
48
|
"description": "Expert in system architecture, design patterns, and cross-project structure. Best for high-level analysis.",
|
|
40
49
|
"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
50
|
"model": "gemma4:31b-cloud",
|
|
51
|
+
"backend": "ollama",
|
|
42
52
|
"active": True
|
|
43
53
|
},
|
|
44
54
|
{
|
|
@@ -47,6 +57,7 @@ DEFAULTS = {
|
|
|
47
57
|
"description": "Specializes in deep code analysis, bug hunting, and tracing execution paths.",
|
|
48
58
|
"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
59
|
"model": "gemma4:31b-cloud",
|
|
60
|
+
"backend": "ollama",
|
|
50
61
|
"active": True
|
|
51
62
|
},
|
|
52
63
|
{
|
|
@@ -55,6 +66,7 @@ DEFAULTS = {
|
|
|
55
66
|
"description": "Focuses on analyzing project memory, facts, and insights.",
|
|
56
67
|
"system_prompt": "You are the Memory Analyst. Rely heavily on memory tools and facts to spot trends. Connect current issues to past context.",
|
|
57
68
|
"model": "gemma4:31b-cloud",
|
|
69
|
+
"backend": "ollama",
|
|
58
70
|
"active": True
|
|
59
71
|
}
|
|
60
72
|
],
|
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
import atexit
|
|
4
4
|
import json
|
|
5
5
|
import logging
|
|
6
|
-
import os
|
|
7
6
|
import socket
|
|
8
7
|
import sys
|
|
9
8
|
import threading
|
|
@@ -16,11 +15,11 @@ _PROJECT_ROOT = Path(__file__).resolve().parent.parent
|
|
|
16
15
|
if str(_PROJECT_ROOT) not in sys.path:
|
|
17
16
|
sys.path.insert(0, str(_PROJECT_ROOT))
|
|
18
17
|
|
|
19
|
-
from flask import Flask, Response, jsonify, request
|
|
18
|
+
from flask import Flask, Response, jsonify, request # noqa: E402
|
|
20
19
|
|
|
21
20
|
from oracle.config import ORACLE_DIR, load_config, save_config # noqa: E402
|
|
22
21
|
from oracle.mcp_oracle import mcp_url, start_mcp_thread # noqa: E402
|
|
23
|
-
from oracle.services import api_auth # noqa: E402
|
|
22
|
+
from oracle.services import api_auth, local_session # noqa: E402
|
|
24
23
|
from oracle.services.activity_reporter import ActivityReporter # noqa: E402
|
|
25
24
|
from oracle.services.api_auth import extract_bearer # noqa: E402
|
|
26
25
|
from oracle.services.api_auth import verify as verify_api_key # noqa: E402
|
|
@@ -68,6 +67,7 @@ def _init_services():
|
|
|
68
67
|
base_url=_cfg.get("ollama_base_url", "https://ollama.com"),
|
|
69
68
|
model=_cfg.get("model", "gemma4:31b-cloud"),
|
|
70
69
|
api_key=_cfg.get("ollama_api_key", ""),
|
|
70
|
+
cache_ttl_sec=int(_cfg.get("llm_cache_ttl_sec", 86400)),
|
|
71
71
|
)
|
|
72
72
|
# Verify model works on startup (background thread to avoid blocking)
|
|
73
73
|
def _verify():
|
|
@@ -80,7 +80,10 @@ def _init_services():
|
|
|
80
80
|
_model_verified = False
|
|
81
81
|
logging.getLogger("oracle").warning("Ollama unreachable — model not verified")
|
|
82
82
|
threading.Thread(target=_verify, daemon=True, name="oracle-model-verify").start()
|
|
83
|
-
_scanner = ProjectScanner(
|
|
83
|
+
_scanner = ProjectScanner(
|
|
84
|
+
hub_url=_cfg.get("hub_url", "http://localhost:3330"),
|
|
85
|
+
ttl=float(_cfg.get("scanner_ttl_seconds", 20)),
|
|
86
|
+
)
|
|
84
87
|
_reader = MemoryReader()
|
|
85
88
|
_checker = HealthChecker(_reader)
|
|
86
89
|
_writer = MemoryWriter()
|
|
@@ -89,6 +92,8 @@ def _init_services():
|
|
|
89
92
|
_chat_store = ChatStore()
|
|
90
93
|
_c3_bridge = C3Bridge(scanner=_scanner)
|
|
91
94
|
_federated = FederatedGraph(reader=_reader, cross_memory=_cross_memory, ollama_bridge=_bridge)
|
|
95
|
+
# Reporter before ReviewAgent: the review loop emits the scheduled digest.
|
|
96
|
+
_activity_reporter = ActivityReporter(scanner=_scanner, ollama_bridge=_bridge)
|
|
92
97
|
_agent = ReviewAgent(
|
|
93
98
|
scanner=_scanner,
|
|
94
99
|
reader=_reader,
|
|
@@ -98,8 +103,8 @@ def _init_services():
|
|
|
98
103
|
writer=_writer,
|
|
99
104
|
interval=int(_cfg.get("review_interval_seconds", 1800)),
|
|
100
105
|
federated_graph=_federated,
|
|
106
|
+
activity_reporter=_activity_reporter,
|
|
101
107
|
)
|
|
102
|
-
_activity_reporter = ActivityReporter(scanner=_scanner, ollama_bridge=_bridge)
|
|
103
108
|
_chat_engine = ChatEngine(
|
|
104
109
|
bridge=_bridge,
|
|
105
110
|
reader=_reader,
|
|
@@ -122,9 +127,10 @@ def _init_services():
|
|
|
122
127
|
# ── CORS ──────────────────────────────────────────────────
|
|
123
128
|
# Localhost security guard + scoped CORS (replaces the previous wildcard CORS).
|
|
124
129
|
# Host-header allowlist + Origin/Referer CSRF guard. Bearer auth on
|
|
125
|
-
# /api/discovery/* (see _discovery_auth_guard below)
|
|
126
|
-
#
|
|
127
|
-
#
|
|
130
|
+
# /api/discovery/* (see _discovery_auth_guard below) and the local write gate
|
|
131
|
+
# (_local_write_guard: session cookie or Bearer on every other mutating
|
|
132
|
+
# /api/* call) still apply on top; this guard blocks cross-origin browsers,
|
|
133
|
+
# the write gate blocks unauthenticated local processes.
|
|
128
134
|
from core.web_security import (
|
|
129
135
|
allowed_hostnames as _allowed_hostnames,
|
|
130
136
|
)
|
|
@@ -155,10 +161,90 @@ def _discovery_auth_guard():
|
|
|
155
161
|
return None
|
|
156
162
|
|
|
157
163
|
|
|
164
|
+
# ── Local write gate ──────────────────────────────────────
|
|
165
|
+
@app.before_request
|
|
166
|
+
def _local_write_guard():
|
|
167
|
+
"""Auth gate for mutating local API calls (everything except Discovery).
|
|
168
|
+
|
|
169
|
+
Requires either the per-boot dashboard session cookie (issued on ``GET /``
|
|
170
|
+
to loopback browsers) or the Discovery Bearer token. Default-deny: any
|
|
171
|
+
future mutating ``/api/*`` endpoint is covered automatically. Closes the
|
|
172
|
+
rotate-then-read kill chain — previously any local process could POST
|
|
173
|
+
/api/apikey/rotate unauthenticated and read the fresh token, defeating
|
|
174
|
+
the Bearer gates on /api/config and /api/discovery/*.
|
|
175
|
+
"""
|
|
176
|
+
path = request.path or ""
|
|
177
|
+
if not path.startswith("/api/") or path.startswith("/api/discovery"):
|
|
178
|
+
return None
|
|
179
|
+
if request.method in ("GET", "HEAD", "OPTIONS"):
|
|
180
|
+
return None
|
|
181
|
+
if verify_api_key(extract_bearer(request.headers.get("Authorization"))):
|
|
182
|
+
return None
|
|
183
|
+
if local_session.verify(request.cookies.get(local_session.COOKIE_NAME)):
|
|
184
|
+
return None
|
|
185
|
+
return jsonify({"error": "unauthorized"}), 401
|
|
186
|
+
|
|
187
|
+
|
|
158
188
|
# ── Static ────────────────────────────────────────────────
|
|
189
|
+
|
|
190
|
+
# JS load order for the concatenated Oracle UI build (mirrors cli/hub_server.py).
|
|
191
|
+
# One shared script scope: function declarations hoist across files, and
|
|
192
|
+
# app.js (the init IIFE) must stay LAST.
|
|
193
|
+
_ORACLE_JS_FILES = [
|
|
194
|
+
"ui/core.js",
|
|
195
|
+
"ui/busy.js",
|
|
196
|
+
"ui/theme_tabs.js",
|
|
197
|
+
"ui/crossgraph.js",
|
|
198
|
+
"ui/header.js",
|
|
199
|
+
"ui/projects.js",
|
|
200
|
+
"ui/insights.js",
|
|
201
|
+
"ui/activity.js",
|
|
202
|
+
"ui/suggestions.js",
|
|
203
|
+
"ui/settings.js",
|
|
204
|
+
"ui/agents.js",
|
|
205
|
+
"ui/chat/markdown.js",
|
|
206
|
+
"ui/chat/conversations.js",
|
|
207
|
+
"ui/chat/stream_renderer.js",
|
|
208
|
+
"ui/chat/toolbar.js",
|
|
209
|
+
"ui/chat/input.js",
|
|
210
|
+
"ui/chat/send.js",
|
|
211
|
+
"ui/app.js",
|
|
212
|
+
]
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
def _build_oracle_html() -> str:
|
|
216
|
+
"""Concatenate oracle_ui.html shell + all JS module files into one response."""
|
|
217
|
+
oracle_dir = Path(__file__).parent
|
|
218
|
+
shell_path = oracle_dir / "oracle_ui.html"
|
|
219
|
+
if not shell_path.exists():
|
|
220
|
+
return "<h1>Oracle UI not found.</h1>"
|
|
221
|
+
|
|
222
|
+
shell = shell_path.read_text(encoding="utf-8")
|
|
223
|
+
|
|
224
|
+
js_parts = []
|
|
225
|
+
for rel in _ORACLE_JS_FILES:
|
|
226
|
+
js_path = oracle_dir / rel
|
|
227
|
+
if js_path.exists():
|
|
228
|
+
js_parts.append(f"// ═══ {rel} ═══\n" + js_path.read_text(encoding="utf-8"))
|
|
229
|
+
|
|
230
|
+
return shell.replace("/* __C3_ORACLE_SCRIPTS__ */", "\n\n".join(js_parts))
|
|
231
|
+
|
|
232
|
+
|
|
233
|
+
# Cache the built HTML (built on first request; cleared on server restart).
|
|
234
|
+
_oracle_html_cache: str | None = None
|
|
235
|
+
|
|
236
|
+
|
|
159
237
|
@app.route("/")
|
|
160
238
|
def index():
|
|
161
|
-
|
|
239
|
+
global _oracle_html_cache
|
|
240
|
+
if _oracle_html_cache is None:
|
|
241
|
+
_oracle_html_cache = _build_oracle_html()
|
|
242
|
+
resp = Response(_oracle_html_cache, mimetype="text/html")
|
|
243
|
+
# Issue the dashboard session cookie only to loopback browsers; remote
|
|
244
|
+
# viewers (LAN bind) can read GET dashboards but cannot mutate.
|
|
245
|
+
if local_session.is_loopback(request.remote_addr):
|
|
246
|
+
local_session.attach_cookie(resp)
|
|
247
|
+
return resp
|
|
162
248
|
|
|
163
249
|
|
|
164
250
|
# ── Health ────────────────────────────────────────────────
|
|
@@ -176,6 +262,7 @@ def api_health():
|
|
|
176
262
|
return jsonify({
|
|
177
263
|
"status": "ok",
|
|
178
264
|
"service": "c3-oracle",
|
|
265
|
+
"version": _c3_version(),
|
|
179
266
|
"model": _cfg.get("model", "gemma4:31b-cloud"),
|
|
180
267
|
"ollama_available": ollama_ok,
|
|
181
268
|
"model_verified": _model_verified,
|
|
@@ -206,11 +293,9 @@ _CONFIG_SETTABLE_KEYS = frozenset(_CONFIG_DEFAULTS.keys())
|
|
|
206
293
|
@app.route("/api/config", methods=["POST"])
|
|
207
294
|
def api_config_set():
|
|
208
295
|
global _cfg
|
|
209
|
-
#
|
|
210
|
-
# repoint ollama_base_url, so it
|
|
211
|
-
|
|
212
|
-
if not verify_api_key(token):
|
|
213
|
-
return jsonify({"error": "unauthorized"}), 401
|
|
296
|
+
# Auth is enforced by _local_write_guard (session cookie or Bearer): this
|
|
297
|
+
# endpoint can disable Discovery auth or repoint ollama_base_url, so it
|
|
298
|
+
# must never be reachable unauthenticated.
|
|
214
299
|
body = request.get_json(silent=True) or {}
|
|
215
300
|
if not isinstance(body, dict):
|
|
216
301
|
return jsonify({"error": "body must be a JSON object"}), 400
|
|
@@ -258,7 +343,8 @@ def api_projects():
|
|
|
258
343
|
|
|
259
344
|
@app.route("/api/projects/scan", methods=["POST"])
|
|
260
345
|
def api_projects_scan():
|
|
261
|
-
|
|
346
|
+
# Explicit Scan action bypasses the scanner's TTL cache.
|
|
347
|
+
projects = _scanner.discover(force=True) if _scanner else []
|
|
262
348
|
return jsonify({"scanned": len(projects), "projects": projects})
|
|
263
349
|
|
|
264
350
|
|
|
@@ -635,6 +721,23 @@ def api_chat_conversation_state(conv_id):
|
|
|
635
721
|
|
|
636
722
|
|
|
637
723
|
# ── Activity digest (Oracle UI) ───────────────────────────
|
|
724
|
+
@app.route("/api/activity/digest/latest", methods=["GET"])
|
|
725
|
+
def api_activity_digest_latest():
|
|
726
|
+
"""Most recent SCHEDULED digest (written by the review loop), or null.
|
|
727
|
+
|
|
728
|
+
On-demand digests via /api/activity/digest are not persisted here; this
|
|
729
|
+
serves ~/.c3/oracle/activity_digests/latest.json.
|
|
730
|
+
"""
|
|
731
|
+
latest = ORACLE_DIR / "activity_digests" / "latest.json"
|
|
732
|
+
try:
|
|
733
|
+
if latest.is_file():
|
|
734
|
+
return Response(latest.read_text(encoding="utf-8"),
|
|
735
|
+
mimetype="application/json")
|
|
736
|
+
except Exception as e:
|
|
737
|
+
return jsonify({"error": str(e)}), 500
|
|
738
|
+
return jsonify({"digest": None, "generated_at": None})
|
|
739
|
+
|
|
740
|
+
|
|
638
741
|
@app.route("/api/activity/digest", methods=["GET"])
|
|
639
742
|
def api_activity_digest():
|
|
640
743
|
"""Cross-project activity digest for the Oracle UI.
|
|
@@ -740,7 +843,7 @@ def api_discovery_mcp_info():
|
|
|
740
843
|
})
|
|
741
844
|
|
|
742
845
|
|
|
743
|
-
# ── Discovery API key management (
|
|
846
|
+
# ── Discovery API key management (mutations gated by _local_write_guard) ──
|
|
744
847
|
def _apikey_status(reveal: bool = False) -> dict:
|
|
745
848
|
"""Status payload for the Discovery API token + connection info.
|
|
746
849
|
|
|
@@ -786,12 +889,14 @@ def _apikey_status(reveal: bool = False) -> dict:
|
|
|
786
889
|
def api_apikey_get():
|
|
787
890
|
"""Return Discovery API token status + connection info.
|
|
788
891
|
|
|
789
|
-
The unmasked token is only included when the caller presents a valid
|
|
790
|
-
token
|
|
791
|
-
HTTP unauthenticated).
|
|
892
|
+
The unmasked token is only included when the caller presents a valid
|
|
893
|
+
Bearer token or the dashboard session cookie; otherwise only the masked
|
|
894
|
+
form is returned (never the raw key over HTTP unauthenticated).
|
|
792
895
|
"""
|
|
793
896
|
try:
|
|
794
|
-
reveal = verify_api_key(
|
|
897
|
+
reveal = verify_api_key(
|
|
898
|
+
extract_bearer(request.headers.get("Authorization"))
|
|
899
|
+
) or local_session.verify(request.cookies.get(local_session.COOKIE_NAME))
|
|
795
900
|
return jsonify(_apikey_status(reveal=reveal))
|
|
796
901
|
except Exception as e:
|
|
797
902
|
return jsonify({"error": str(e)}), 500
|