code-context-control 2.44.1__tar.gz → 2.45.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.44.1 → code_context_control-2.45.0}/PKG-INFO +1 -1
- {code_context_control-2.44.1 → code_context_control-2.45.0}/cli/c3.py +2 -2
- {code_context_control-2.44.1 → code_context_control-2.45.0}/cli/guide/tools.html +48 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/cli/hub_server.py +282 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/cli/hub_ui/app.js +20 -8
- {code_context_control-2.44.1 → code_context_control-2.45.0}/cli/hub_ui/components/drill_panel.js +2 -0
- code_context_control-2.45.0/cli/hub_ui/components/drill_tasks.js +325 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/cli/hub_ui/components/drill_views.js +1 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/cli/hub_ui/components/project_card.js +7 -0
- code_context_control-2.45.0/cli/hub_ui/components/task_board.js +277 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/cli/hub_ui/components/topbar.js +22 -1
- {code_context_control-2.44.1 → code_context_control-2.45.0}/cli/mcp_server.py +49 -2
- {code_context_control-2.44.1 → code_context_control-2.45.0}/cli/server.py +159 -0
- code_context_control-2.45.0/cli/tools/tasks.py +244 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/cli/ui/api.js +4 -1
- {code_context_control-2.44.1 → code_context_control-2.45.0}/cli/ui/app.js +4 -0
- code_context_control-2.45.0/cli/ui/components/tasks.js +287 -0
- code_context_control-2.45.0/cli/ui/pm_shared.js +74 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/code_context_control.egg-info/PKG-INFO +1 -1
- {code_context_control-2.44.1 → code_context_control-2.45.0}/code_context_control.egg-info/SOURCES.txt +9 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/core/config.py +4 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/pyproject.toml +1 -1
- {code_context_control-2.44.1 → code_context_control-2.45.0}/services/runtime.py +6 -0
- code_context_control-2.45.0/services/task_store.py +578 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/tests/test_hub_server_smoke.py +14 -0
- code_context_control-2.45.0/tests/test_pm_api.py +243 -0
- code_context_control-2.45.0/tests/test_task_store.py +232 -0
- code_context_control-2.45.0/tests/test_task_tool.py +138 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/LICENSE +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/README.md +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/cli/__init__.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/cli/_hook_utils.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/cli/commands/__init__.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/cli/commands/common.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/cli/commands/parser.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/cli/docs.html +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/cli/edits.html +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/cli/guide/bitbucket.html +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/cli/guide/getting-started.html +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/cli/guide/index.html +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/cli/guide/oracle.html +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/cli/guide/shared.css +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/cli/guide/workflow.html +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/cli/hook_auto_snapshot.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/cli/hook_c3_signal.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/cli/hook_c3read.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/cli/hook_dispatch.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/cli/hook_edit_ledger.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/cli/hook_edit_unlock.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/cli/hook_filter.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/cli/hook_ghost_files.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/cli/hook_pretool_enforce.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/cli/hook_read.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/cli/hook_session_stats.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/cli/hook_terse_advisor.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/cli/hub.html +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/cli/hub_ui/components/add_project.js +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/cli/hub_ui/components/config_editor.js +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/cli/hub_ui/components/drill_health.js +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/cli/hub_ui/components/global_search.js +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/cli/hub_ui/components/mcp_manager.js +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/cli/hub_ui/components/modals.js +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/cli/hub_ui/components/project_tree.js +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/cli/hub_ui/components/session_drawer.js +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/cli/hub_ui/components/settings_modal.js +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/cli/hub_ui/components/sidebar.js +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/cli/hub_ui/components/summary_bar.js +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/cli/hub_ui/components/toasts.js +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/cli/hub_ui/state.js +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/cli/hub_ui.html +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/cli/mcp_proxy.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/cli/tools/__init__.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/cli/tools/_helpers.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/cli/tools/agent.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/cli/tools/bitbucket.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/cli/tools/compress.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/cli/tools/delegate.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/cli/tools/edit.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/cli/tools/edits.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/cli/tools/federate.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/cli/tools/filter.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/cli/tools/impact.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/cli/tools/memory.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/cli/tools/project.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/cli/tools/read.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/cli/tools/search.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/cli/tools/session.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/cli/tools/shell.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/cli/tools/status.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/cli/tools/validate.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/cli/ui/components/bitbucket.js +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/cli/ui/components/chat.js +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/cli/ui/components/dashboard.js +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/cli/ui/components/edits.js +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/cli/ui/components/instructions.js +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/cli/ui/components/memory.js +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/cli/ui/components/sessions.js +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/cli/ui/components/settings.js +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/cli/ui/components/sidebar.js +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/cli/ui/icons.js +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/cli/ui/shared.js +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/cli/ui/theme.js +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/cli/ui.html +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/cli/ui_legacy.html +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/cli/ui_nano.html +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/code_context_control.egg-info/dependency_links.txt +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/code_context_control.egg-info/entry_points.txt +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/code_context_control.egg-info/requires.txt +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/code_context_control.egg-info/top_level.txt +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/core/__init__.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/core/ide.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/core/mcp_toml.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/core/web_security.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/oracle/__init__.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/oracle/config.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/oracle/mcp_oracle.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/oracle/oracle.html +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/oracle/oracle_server.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/oracle/services/__init__.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/oracle/services/activity_reporter.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/oracle/services/api_auth.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/oracle/services/c3_bridge.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/oracle/services/chat_engine.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/oracle/services/chat_store.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/oracle/services/cross_memory.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/oracle/services/federated_graph.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/oracle/services/health_checker.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/oracle/services/insight_engine.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/oracle/services/memory_reader.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/oracle/services/memory_writer.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/oracle/services/ollama_bridge.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/oracle/services/project_scanner.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/oracle/services/review_agent.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/oracle/services/tool_executor.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/oracle/services/tool_registry.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/services/__init__.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/services/activity_log.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/services/agent_base.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/services/agents.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/services/auto_memory.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/services/bench/__init__.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/services/bench/external/__init__.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/services/bench/external/aider_polyglot.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/services/bench/external/swe_bench.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/services/benchmark_dashboard.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/services/bitbucket_client.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/services/bitbucket_credentials.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/services/circuit_breaker.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/services/claude_md.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/services/compressor.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/services/context_snapshot.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/services/conversation_store.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/services/doc_index.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/services/e2e_benchmark.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/services/e2e_evaluator.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/services/e2e_tasks.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/services/edit_ledger.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/services/embedding_index.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/services/error_reporting.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/services/file_memory.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/services/git_context.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/services/hub_service.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/services/indexer.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/services/memory.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/services/memory_consolidator.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/services/memory_graph.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/services/memory_grounder.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/services/memory_scorer.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/services/metrics.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/services/notifications.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/services/ollama_client.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/services/output_filter.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/services/parser.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/services/project_manager.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/services/project_runtime.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/services/protocol.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/services/proxy_state.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/services/retention.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/services/retrieval_broker.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/services/router.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/services/session_benchmark.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/services/session_manager.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/services/session_preloader.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/services/subprojects.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/services/telemetry.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/services/text_index.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/services/tool_classifier.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/services/transcript_index.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/services/validation_cache.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/services/vector_store.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/services/version_tracker.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/services/watcher.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/services/win_subprocess.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/setup.cfg +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/tests/test_activity_reporter.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/tests/test_aider_polyglot.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/tests/test_bitbucket_cli_smoke.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/tests/test_bitbucket_client.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/tests/test_bitbucket_config_fallback.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/tests/test_bitbucket_credentials.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/tests/test_bitbucket_tool.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/tests/test_c3_shell.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/tests/test_circuit_breaker.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/tests/test_claude_md_merge.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/tests/test_cli_smoke.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/tests/test_compressor_large_file.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/tests/test_delegate_cascade.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/tests/test_e2e_benchmark.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/tests/test_edit_ledger_hook.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/tests/test_edit_normalization.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/tests/test_enforcement_flip.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/tests/test_federated_graph.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/tests/test_filter_backoff.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/tests/test_ghost_files.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/tests/test_ghost_generation.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/tests/test_git_branch_awareness.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/tests/test_hook_dispatch.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/tests/test_hook_pretool_enforce.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/tests/test_hook_smoke.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/tests/test_hook_state.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/tests/test_hub_inspect_api.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/tests/test_install_mcp_entrypoint.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/tests/test_lazy_store_init.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/tests/test_mcp_host_guard.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/tests/test_mcp_server_smoke.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/tests/test_mcp_toml.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/tests/test_memory_graph_api.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/tests/test_memory_system.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/tests/test_notification_dedup.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/tests/test_notification_discipline.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/tests/test_oracle_api_auth.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/tests/test_oracle_apikey_api.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/tests/test_oracle_discovery_api.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/tests/test_oracle_security_fixes.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/tests/test_output_filter.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/tests/test_permissions.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/tests/test_project_manager.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/tests/test_project_manager_merge.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/tests/test_project_tool.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/tests/test_read_coercion.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/tests/test_response_boilerplate.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/tests/test_retention.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/tests/test_service_durability.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/tests/test_session_benchmark.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/tests/test_session_budget.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/tests/test_shell_robustness.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/tests/test_subproject_exclusion.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/tests/test_subproject_federation.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/tests/test_subprojects.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/tests/test_swe_bench.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/tests/test_token_telemetry.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/tests/test_tool_registry.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/tests/test_upgrade_and_version.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/tests/test_validate.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/tests/test_web_security.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/tests/test_windows_reliability.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/tui/__init__.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/tui/backend.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/tui/main.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/tui/screens/__init__.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/tui/screens/benchmark_view.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/tui/screens/claudemd_view.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/tui/screens/compress_view.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/tui/screens/index_view.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/tui/screens/init_view.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/tui/screens/mcp_view.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/tui/screens/optimize_view.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/tui/screens/pipe_view.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/tui/screens/projects_view.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/tui/screens/search_view.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/tui/screens/session_view.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/tui/screens/stats.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/tui/screens/ui_view.py +0 -0
- {code_context_control-2.44.1 → code_context_control-2.45.0}/tui/theme.tcss +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: code-context-control
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.45.0
|
|
4
4
|
Summary: Local code-intelligence layer for AI coding tools (Claude Code, Codex, Gemini, Copilot). Retrieve less, read less, edit safer.
|
|
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.45.0"
|
|
89
89
|
|
|
90
90
|
|
|
91
91
|
def _command_deps() -> CommandDeps:
|
|
@@ -239,7 +239,7 @@ _C3_MCP_ALLOW = [
|
|
|
239
239
|
"mcp__c3__c3_memory", "mcp__c3__c3_validate", "mcp__c3__c3_edit",
|
|
240
240
|
"mcp__c3__c3_agent", "mcp__c3__c3_delegate", "mcp__c3__c3_edits",
|
|
241
241
|
"mcp__c3__c3_impact", "mcp__c3__c3_shell", "mcp__c3__c3_bitbucket",
|
|
242
|
-
"mcp__c3__c3_project",
|
|
242
|
+
"mcp__c3__c3_project", "mcp__c3__c3_task",
|
|
243
243
|
]
|
|
244
244
|
|
|
245
245
|
# Obsolete MCP tool names from earlier C3 versions. `c3 permissions clean`
|
|
@@ -121,6 +121,7 @@
|
|
|
121
121
|
</div>
|
|
122
122
|
<div class="sidebar-section">
|
|
123
123
|
<div class="sidebar-label">SCM</div>
|
|
124
|
+
<a href="#c3_task" class="sidebar-link"><span class="icon">✅</span> c3_task</a>
|
|
124
125
|
<a href="#c3_bitbucket" class="sidebar-link"><span class="icon">🪣</span> c3_bitbucket</a>
|
|
125
126
|
</div>
|
|
126
127
|
<div class="sidebar-section">
|
|
@@ -155,6 +156,7 @@
|
|
|
155
156
|
<a href="#c3_delegate" class="toc-item">c3_delegate <span class="cat">AI</span></a>
|
|
156
157
|
<a href="#c3_agent" class="toc-item">c3_agent <span class="cat">AI</span></a>
|
|
157
158
|
<a href="#c3_edits" class="toc-item">c3_edits <span class="cat">Ledger</span></a>
|
|
159
|
+
<a href="#c3_task" class="toc-item">c3_task <span class="cat">PM</span></a>
|
|
158
160
|
<a href="#c3_bitbucket" class="toc-item">c3_bitbucket <span class="cat">SCM</span></a>
|
|
159
161
|
<a href="#c3_project" class="toc-item">c3_project <span class="cat">Multi-project</span></a>
|
|
160
162
|
</div>
|
|
@@ -1090,6 +1092,52 @@ c3_edits(action=<span class="str">'history'</span>, branch=<span class="str">'fe
|
|
|
1090
1092
|
</div>
|
|
1091
1093
|
</div>
|
|
1092
1094
|
|
|
1095
|
+
<!-- c3_task -->
|
|
1096
|
+
<div class="tool-card" id="c3_task">
|
|
1097
|
+
<div class="tool-card-header">
|
|
1098
|
+
<span class="tool-name">c3_task</span>
|
|
1099
|
+
<div class="tag-row">
|
|
1100
|
+
<span class="badge badge-purple">pm</span>
|
|
1101
|
+
<span class="badge">v2.45.0</span>
|
|
1102
|
+
</div>
|
|
1103
|
+
<span class="tool-tagline">Durable per-project tasks, milestones, and decision notes — the project-management layer</span>
|
|
1104
|
+
</div>
|
|
1105
|
+
<div class="tool-card-body">
|
|
1106
|
+
<p class="tool-desc">Every C3 project carries a PM store at <code>.c3/pm/pm.json</code>: tasks with status (backlog / in_progress / blocked / done), priority (p0–p3), due dates, tags, and code links (files, commits, edit-ledger entries); milestones with computed progress; and a decision-note log separate from AI memory. The same store powers the Hub's Tasks tab and kanban board, the per-project UI's Tasks tab, and this tool. Task ids accept any unique prefix (≥4 chars); milestones resolve by id or unique name. Read actions are plan-mode-safe. Ephemeral session plans stay in <code>c3_session(action='plan')</code>.</p>
|
|
1107
|
+
|
|
1108
|
+
<h4>Actions</h4>
|
|
1109
|
+
<table class="params-table">
|
|
1110
|
+
<thead><tr><th>Action</th><th>Group</th><th>Description</th></tr></thead>
|
|
1111
|
+
<tbody>
|
|
1112
|
+
<tr><td class="param-name">add</td><td>Write</td><td class="param-desc">Create a task: <code>title</code> + optional description / priority / due_date (YYYY-MM-DD) / tags (CSV) / milestone</td></tr>
|
|
1113
|
+
<tr><td class="param-name">update, done, archive</td><td>Write</td><td class="param-desc"><code>task_id</code> + changed fields; <code>done</code> stamps completion; archive keeps history</td></tr>
|
|
1114
|
+
<tr><td class="param-name">list, get, board</td><td>Read</td><td class="param-desc">Filtered list (status/priority/tags/milestone/query), full detail, kanban columns + milestone progress</td></tr>
|
|
1115
|
+
<tr><td class="param-name">link, unlink</td><td>Write</td><td class="param-desc"><code>task_id</code> + <code>link_type</code> (file | commit | edit) + <code>ref</code> — tie tasks to the code they touch</td></tr>
|
|
1116
|
+
<tr><td class="param-name">milestone_add / _update / _list / _archive</td><td>Both</td><td class="param-desc">Milestones with target dates; list shows progress %; archive detaches its tasks</td></tr>
|
|
1117
|
+
<tr><td class="param-name">note_add, note_list</td><td>Both</td><td class="param-desc">Dated notes; <code>kind='decision'</code> for the decision log</td></tr>
|
|
1118
|
+
</tbody>
|
|
1119
|
+
</table>
|
|
1120
|
+
|
|
1121
|
+
<h4>Examples</h4>
|
|
1122
|
+
<pre><code><span class="com"># Capture a task while coding</span>
|
|
1123
|
+
c3_task(action=<span class="str">'add'</span>, title=<span class="str">'Harden pm.json against concurrent writes'</span>,
|
|
1124
|
+
priority=<span class="str">'p1'</span>, tags=<span class="str">'pm,backend'</span>)
|
|
1125
|
+
|
|
1126
|
+
<span class="com"># Tie it to the code it touches, then finish it</span>
|
|
1127
|
+
c3_task(action=<span class="str">'link'</span>, task_id=<span class="str">'a1b2c3d4'</span>, link_type=<span class="str">'file'</span>, ref=<span class="str">'services/task_store.py'</span>)
|
|
1128
|
+
c3_task(action=<span class="str">'done'</span>, task_id=<span class="str">'a1b2'</span>)
|
|
1129
|
+
|
|
1130
|
+
<span class="com"># Milestones + the board</span>
|
|
1131
|
+
c3_task(action=<span class="str">'milestone_add'</span>, name=<span class="str">'v2.46'</span>, target_date=<span class="str">'2026-08-01'</span>)
|
|
1132
|
+
c3_task(action=<span class="str">'board'</span>)
|
|
1133
|
+
|
|
1134
|
+
<span class="com"># Record a decision</span>
|
|
1135
|
+
c3_task(action=<span class="str">'note_add'</span>, note=<span class="str">'Kanban rank uses float sort keys'</span>, kind=<span class="str">'decision'</span>)</code></pre>
|
|
1136
|
+
|
|
1137
|
+
<p class="tool-desc"><strong>Surfaces:</strong> the Hub shows a Tasks tab per project (drill-in panel), <code>☑ N</code> open-task chips on cards, and a global kanban board behind the Projects | Tasks switcher. Hub mutations audit <code>pm_write</code> events to the project's activity log. Disable with <code>hybrid.pm.enabled=false</code>.</p>
|
|
1138
|
+
</div>
|
|
1139
|
+
</div>
|
|
1140
|
+
|
|
1093
1141
|
<!-- c3_bitbucket -->
|
|
1094
1142
|
<div class="tool-card" id="c3_bitbucket">
|
|
1095
1143
|
<div class="tool-card-header">
|
|
@@ -67,6 +67,7 @@ _HUB_CONFIG_DEFAULTS = {
|
|
|
67
67
|
"auto_open_browser": True,
|
|
68
68
|
"theme": "dark",
|
|
69
69
|
"projects_view": "list",
|
|
70
|
+
"main_view": "projects",
|
|
70
71
|
"oracle_url": "",
|
|
71
72
|
}
|
|
72
73
|
|
|
@@ -319,6 +320,7 @@ _HUB_JS_FILES = [
|
|
|
319
320
|
"ui/icons.js",
|
|
320
321
|
"ui/api.js",
|
|
321
322
|
"ui/shared.js",
|
|
323
|
+
"ui/pm_shared.js",
|
|
322
324
|
"hub_ui/state.js",
|
|
323
325
|
"hub_ui/components/toasts.js",
|
|
324
326
|
"hub_ui/components/topbar.js",
|
|
@@ -327,10 +329,12 @@ _HUB_JS_FILES = [
|
|
|
327
329
|
"hub_ui/components/summary_bar.js",
|
|
328
330
|
"hub_ui/components/project_card.js",
|
|
329
331
|
"hub_ui/components/project_tree.js",
|
|
332
|
+
"hub_ui/components/task_board.js",
|
|
330
333
|
"hub_ui/components/session_drawer.js",
|
|
331
334
|
"hub_ui/components/drill_panel.js",
|
|
332
335
|
"hub_ui/components/drill_views.js",
|
|
333
336
|
"hub_ui/components/drill_health.js",
|
|
337
|
+
"hub_ui/components/drill_tasks.js",
|
|
334
338
|
"hub_ui/components/config_editor.js",
|
|
335
339
|
"hub_ui/components/mcp_manager.js",
|
|
336
340
|
"hub_ui/components/global_search.js",
|
|
@@ -429,6 +433,11 @@ def api_hub_config_set():
|
|
|
429
433
|
if projects_view not in {"list", "grid"}:
|
|
430
434
|
return jsonify({"error": "projects_view must be 'list' or 'grid'"}), 400
|
|
431
435
|
cfg["projects_view"] = projects_view
|
|
436
|
+
if "main_view" in data:
|
|
437
|
+
main_view = str(data["main_view"]).strip().lower()
|
|
438
|
+
if main_view not in {"projects", "board"}:
|
|
439
|
+
return jsonify({"error": "main_view must be 'projects' or 'board'"}), 400
|
|
440
|
+
cfg["main_view"] = main_view
|
|
432
441
|
if "oracle_url" in data:
|
|
433
442
|
cfg["oracle_url"] = str(data["oracle_url"]).strip()
|
|
434
443
|
if "sidebar_group" in data:
|
|
@@ -470,11 +479,13 @@ def _notification_count(project_path: str) -> int:
|
|
|
470
479
|
@app.route("/api/projects", methods=["GET"])
|
|
471
480
|
def api_projects_list():
|
|
472
481
|
try:
|
|
482
|
+
from services.task_store import open_task_count
|
|
473
483
|
projects = _pm().list_projects()
|
|
474
484
|
parent_paths = {os.path.normcase(p["parent_path"]) for p in projects if p.get("parent_path")}
|
|
475
485
|
for p in projects:
|
|
476
486
|
p["notification_count"] = _notification_count(p.get("path", ""))
|
|
477
487
|
p["is_parent"] = os.path.normcase(p.get("path", "")) in parent_paths
|
|
488
|
+
p["open_task_count"] = open_task_count(p.get("path", ""))
|
|
478
489
|
return jsonify(projects)
|
|
479
490
|
except Exception as e:
|
|
480
491
|
return jsonify({"error": str(e)}), 500
|
|
@@ -1463,11 +1474,13 @@ def api_projects_inspect():
|
|
|
1463
1474
|
ledger_total = int(rt.edit_ledger.get_stats().get("total", 0))
|
|
1464
1475
|
except Exception:
|
|
1465
1476
|
ledger_total = 0
|
|
1477
|
+
task_store = getattr(rt, "task_store", None)
|
|
1466
1478
|
counts = {
|
|
1467
1479
|
"facts": len(rt.memory.facts),
|
|
1468
1480
|
"edits": ledger_total,
|
|
1469
1481
|
"sessions": len(rt.session_mgr.list_sessions(500)),
|
|
1470
1482
|
"notifications": _notification_count(resolved["path"]),
|
|
1483
|
+
"tasks_open": task_store.stats()["open"] if task_store else 0,
|
|
1471
1484
|
}
|
|
1472
1485
|
return jsonify({"project": details, "counts": counts})
|
|
1473
1486
|
if view == "memory":
|
|
@@ -1484,6 +1497,13 @@ def api_projects_inspect():
|
|
|
1484
1497
|
})
|
|
1485
1498
|
if view == "sessions":
|
|
1486
1499
|
return jsonify({"sessions": rt.session_mgr.list_sessions(limit)})
|
|
1500
|
+
if view == "tasks":
|
|
1501
|
+
task_store = getattr(rt, "task_store", None)
|
|
1502
|
+
if task_store is None:
|
|
1503
|
+
return jsonify({"board": {"columns": {}, "milestones": [], "stats": {}},
|
|
1504
|
+
"notes": []})
|
|
1505
|
+
return jsonify({"board": task_store.board(),
|
|
1506
|
+
"notes": task_store.list_notes(limit=20)})
|
|
1487
1507
|
return jsonify({"error": f"unknown view '{view}'"}), 400
|
|
1488
1508
|
except Exception as e:
|
|
1489
1509
|
return jsonify({"error": str(e)}), 500
|
|
@@ -1659,6 +1679,268 @@ def api_projects_config_put():
|
|
|
1659
1679
|
return jsonify({"saved": True, "section": section, "config": merged})
|
|
1660
1680
|
|
|
1661
1681
|
|
|
1682
|
+
# ── Project management: tasks / milestones / notes (v2.45.0) ──────────────
|
|
1683
|
+
# Direct TaskStore per request (reload-per-op store — no runtime build needed
|
|
1684
|
+
# for mutations); every write audited to the target project's activity log.
|
|
1685
|
+
|
|
1686
|
+
def _pm_resolve(path: str):
|
|
1687
|
+
"""Resolve a PM request path -> (Path, error_response|None)."""
|
|
1688
|
+
if not path:
|
|
1689
|
+
return None, (jsonify({"error": "path is required"}), 400)
|
|
1690
|
+
try:
|
|
1691
|
+
resolved = _resolve_project_path(path)
|
|
1692
|
+
except ValueError as e:
|
|
1693
|
+
return None, (jsonify({"error": str(e)}), 404)
|
|
1694
|
+
if not (resolved / ".c3").is_dir():
|
|
1695
|
+
return None, (jsonify({"error": "not initialized", "needs_init": True}), 409)
|
|
1696
|
+
return resolved, None
|
|
1697
|
+
|
|
1698
|
+
|
|
1699
|
+
def _pm_store(path):
|
|
1700
|
+
from services.task_store import TaskStore
|
|
1701
|
+
return TaskStore(str(path))
|
|
1702
|
+
|
|
1703
|
+
|
|
1704
|
+
def _pm_audit(path, entity, op, item_id=""):
|
|
1705
|
+
try:
|
|
1706
|
+
ActivityLog(str(path)).log("pm_write", {
|
|
1707
|
+
"entity": entity, "op": op, "id": item_id, "source": "hub"})
|
|
1708
|
+
except Exception:
|
|
1709
|
+
pass
|
|
1710
|
+
|
|
1711
|
+
|
|
1712
|
+
@app.route("/api/projects/pm", methods=["GET"])
|
|
1713
|
+
def api_projects_pm_get():
|
|
1714
|
+
"""Full PM board for one project. Query: path, milestone?, tag?,
|
|
1715
|
+
include_children? (parent rollup), include_archived?"""
|
|
1716
|
+
resolved, err = _pm_resolve((request.args.get("path") or "").strip())
|
|
1717
|
+
if err:
|
|
1718
|
+
return err
|
|
1719
|
+
store = _pm_store(resolved)
|
|
1720
|
+
board = store.board(
|
|
1721
|
+
milestone_id=(request.args.get("milestone") or None),
|
|
1722
|
+
tag=(request.args.get("tag") or None),
|
|
1723
|
+
include_archived=request.args.get("include_archived") == "1",
|
|
1724
|
+
)
|
|
1725
|
+
out = {"path": str(resolved), "board": board, "notes": store.list_notes(limit=100)}
|
|
1726
|
+
if request.args.get("include_children") == "1":
|
|
1727
|
+
children = []
|
|
1728
|
+
try:
|
|
1729
|
+
from services.subprojects import SubprojectManager
|
|
1730
|
+
for c in SubprojectManager(str(resolved)).list():
|
|
1731
|
+
if c["status"] in ("missing_folder", "missing_c3"):
|
|
1732
|
+
continue
|
|
1733
|
+
rows = [t for t in _pm_store(c["path"]).list_tasks(limit=100)
|
|
1734
|
+
if t.get("status") != "done"]
|
|
1735
|
+
children.append({"name": c["name"], "path": c["path"], "tasks": rows})
|
|
1736
|
+
except Exception:
|
|
1737
|
+
pass
|
|
1738
|
+
out["children"] = children
|
|
1739
|
+
return jsonify(out)
|
|
1740
|
+
|
|
1741
|
+
|
|
1742
|
+
@app.route("/api/projects/pm/task", methods=["POST", "PUT", "DELETE"])
|
|
1743
|
+
def api_pm_task():
|
|
1744
|
+
data = request.get_json(force=True) or {}
|
|
1745
|
+
resolved, err = _pm_resolve((data.get("path") or "").strip())
|
|
1746
|
+
if err:
|
|
1747
|
+
return err
|
|
1748
|
+
store = _pm_store(resolved)
|
|
1749
|
+
|
|
1750
|
+
if request.method == "POST":
|
|
1751
|
+
res = store.create_task(
|
|
1752
|
+
data.get("title", ""), description=data.get("description", ""),
|
|
1753
|
+
status=data.get("status") or "backlog",
|
|
1754
|
+
priority=data.get("priority") or "p2",
|
|
1755
|
+
due_date=data.get("due_date") or None,
|
|
1756
|
+
tags=data.get("tags") or [], milestone_id=data.get("milestone_id"),
|
|
1757
|
+
links=data.get("links") or [], created_by="hub")
|
|
1758
|
+
if "error" in res:
|
|
1759
|
+
return jsonify(res), 400
|
|
1760
|
+
_pm_audit(resolved, "task", "create", res["id"])
|
|
1761
|
+
return jsonify({"created": True, "task": res}), 201
|
|
1762
|
+
|
|
1763
|
+
if request.method == "PUT":
|
|
1764
|
+
task_id = (data.get("id") or "").strip()
|
|
1765
|
+
if not task_id:
|
|
1766
|
+
return jsonify({"error": "id is required"}), 400
|
|
1767
|
+
res = None
|
|
1768
|
+
fields = data.get("fields") or {}
|
|
1769
|
+
if fields:
|
|
1770
|
+
res = store.update_task(task_id, **fields)
|
|
1771
|
+
if "error" in res:
|
|
1772
|
+
return jsonify(res), 400
|
|
1773
|
+
move = data.get("move") or {}
|
|
1774
|
+
if move:
|
|
1775
|
+
res = store.move_task(task_id, status=move.get("status"),
|
|
1776
|
+
before_id=move.get("before_id"),
|
|
1777
|
+
after_id=move.get("after_id"))
|
|
1778
|
+
if "error" in res:
|
|
1779
|
+
return jsonify(res), 400
|
|
1780
|
+
if res is None:
|
|
1781
|
+
return jsonify({"error": "fields or move required"}), 400
|
|
1782
|
+
_pm_audit(resolved, "task", "update", res["id"])
|
|
1783
|
+
return jsonify({"updated": True, "task": res})
|
|
1784
|
+
|
|
1785
|
+
# DELETE: archive by id, or purge all archived with {purge: true}
|
|
1786
|
+
if data.get("purge"):
|
|
1787
|
+
res = store.purge_archived("task")
|
|
1788
|
+
_pm_audit(resolved, "task", "purge")
|
|
1789
|
+
return jsonify(res)
|
|
1790
|
+
task_id = (data.get("id") or "").strip()
|
|
1791
|
+
if not task_id:
|
|
1792
|
+
return jsonify({"error": "id is required"}), 400
|
|
1793
|
+
res = store.archive_task(task_id)
|
|
1794
|
+
if "error" in res:
|
|
1795
|
+
return jsonify(res), 400
|
|
1796
|
+
_pm_audit(resolved, "task", "archive", res["id"])
|
|
1797
|
+
return jsonify({"archived": True, "task": res})
|
|
1798
|
+
|
|
1799
|
+
|
|
1800
|
+
@app.route("/api/projects/pm/milestone", methods=["POST", "PUT", "DELETE"])
|
|
1801
|
+
def api_pm_milestone():
|
|
1802
|
+
data = request.get_json(force=True) or {}
|
|
1803
|
+
resolved, err = _pm_resolve((data.get("path") or "").strip())
|
|
1804
|
+
if err:
|
|
1805
|
+
return err
|
|
1806
|
+
store = _pm_store(resolved)
|
|
1807
|
+
|
|
1808
|
+
if request.method == "POST":
|
|
1809
|
+
res = store.create_milestone(data.get("name", ""),
|
|
1810
|
+
description=data.get("description", ""),
|
|
1811
|
+
target_date=data.get("target_date") or None)
|
|
1812
|
+
if "error" in res:
|
|
1813
|
+
return jsonify(res), 400
|
|
1814
|
+
_pm_audit(resolved, "milestone", "create", res["id"])
|
|
1815
|
+
return jsonify({"created": True, "milestone": res}), 201
|
|
1816
|
+
|
|
1817
|
+
ms_id = (data.get("id") or "").strip()
|
|
1818
|
+
if not ms_id:
|
|
1819
|
+
return jsonify({"error": "id is required"}), 400
|
|
1820
|
+
|
|
1821
|
+
if request.method == "PUT":
|
|
1822
|
+
res = store.update_milestone(ms_id, **(data.get("fields") or {}))
|
|
1823
|
+
if "error" in res:
|
|
1824
|
+
return jsonify(res), 400
|
|
1825
|
+
_pm_audit(resolved, "milestone", "update", res["id"])
|
|
1826
|
+
return jsonify({"updated": True, "milestone": res})
|
|
1827
|
+
|
|
1828
|
+
res = store.archive_milestone(ms_id) # DELETE = archive + detach tasks
|
|
1829
|
+
if "error" in res:
|
|
1830
|
+
return jsonify(res), 400
|
|
1831
|
+
_pm_audit(resolved, "milestone", "archive", res["id"])
|
|
1832
|
+
return jsonify({"archived": True, "milestone": res})
|
|
1833
|
+
|
|
1834
|
+
|
|
1835
|
+
@app.route("/api/projects/pm/note", methods=["POST", "PUT", "DELETE"])
|
|
1836
|
+
def api_pm_note():
|
|
1837
|
+
data = request.get_json(force=True) or {}
|
|
1838
|
+
resolved, err = _pm_resolve((data.get("path") or "").strip())
|
|
1839
|
+
if err:
|
|
1840
|
+
return err
|
|
1841
|
+
store = _pm_store(resolved)
|
|
1842
|
+
|
|
1843
|
+
if request.method == "POST":
|
|
1844
|
+
res = store.add_note(data.get("text", ""), kind=data.get("kind") or "note",
|
|
1845
|
+
tags=data.get("tags") or [],
|
|
1846
|
+
task_id=data.get("task_id"), author="hub")
|
|
1847
|
+
if "error" in res:
|
|
1848
|
+
return jsonify(res), 400
|
|
1849
|
+
_pm_audit(resolved, "note", "create", res["id"])
|
|
1850
|
+
return jsonify({"created": True, "note": res}), 201
|
|
1851
|
+
|
|
1852
|
+
note_id = (data.get("id") or "").strip()
|
|
1853
|
+
if not note_id:
|
|
1854
|
+
return jsonify({"error": "id is required"}), 400
|
|
1855
|
+
|
|
1856
|
+
if request.method == "PUT":
|
|
1857
|
+
res = store.update_note(note_id, **(data.get("fields") or {}))
|
|
1858
|
+
if "error" in res:
|
|
1859
|
+
return jsonify(res), 400
|
|
1860
|
+
_pm_audit(resolved, "note", "update", res["id"])
|
|
1861
|
+
return jsonify({"updated": True, "note": res})
|
|
1862
|
+
|
|
1863
|
+
res = store.archive_note(note_id)
|
|
1864
|
+
if "error" in res:
|
|
1865
|
+
return jsonify(res), 400
|
|
1866
|
+
_pm_audit(resolved, "note", "archive", res["id"])
|
|
1867
|
+
return jsonify({"archived": True, "note": res})
|
|
1868
|
+
|
|
1869
|
+
|
|
1870
|
+
@app.route("/api/projects/pm/link", methods=["POST"])
|
|
1871
|
+
def api_pm_link():
|
|
1872
|
+
data = request.get_json(force=True) or {}
|
|
1873
|
+
resolved, err = _pm_resolve((data.get("path") or "").strip())
|
|
1874
|
+
if err:
|
|
1875
|
+
return err
|
|
1876
|
+
task_id = (data.get("id") or "").strip()
|
|
1877
|
+
link = data.get("link") or {}
|
|
1878
|
+
op = (data.get("op") or "add").strip()
|
|
1879
|
+
if not task_id or not link.get("type") or not link.get("ref"):
|
|
1880
|
+
return jsonify({"error": "id and link {type, ref} are required"}), 400
|
|
1881
|
+
if op not in ("add", "remove"):
|
|
1882
|
+
return jsonify({"error": "op must be add|remove"}), 400
|
|
1883
|
+
store = _pm_store(resolved)
|
|
1884
|
+
if op == "add":
|
|
1885
|
+
res = store.add_link(task_id, link["type"], link["ref"],
|
|
1886
|
+
label=link.get("label", ""))
|
|
1887
|
+
else:
|
|
1888
|
+
res = store.remove_link(task_id, link["type"], link["ref"])
|
|
1889
|
+
if "error" in res:
|
|
1890
|
+
return jsonify(res), 400
|
|
1891
|
+
_pm_audit(resolved, "link", op, res["id"])
|
|
1892
|
+
return jsonify({"task": res})
|
|
1893
|
+
|
|
1894
|
+
|
|
1895
|
+
@app.route("/api/pm/global", methods=["GET"])
|
|
1896
|
+
def api_pm_global():
|
|
1897
|
+
"""Open tasks across every registered project (raw registry — no port probes)."""
|
|
1898
|
+
try:
|
|
1899
|
+
limit = max(1, min(int(request.args.get("limit") or 500), 1000))
|
|
1900
|
+
except ValueError:
|
|
1901
|
+
limit = 500
|
|
1902
|
+
status_filter = (request.args.get("status") or "").strip()
|
|
1903
|
+
from services.task_store import TaskStore
|
|
1904
|
+
|
|
1905
|
+
tasks, skipped, by_project = [], [], {}
|
|
1906
|
+
entries = _pm()._read_projects()
|
|
1907
|
+
for p in entries:
|
|
1908
|
+
ppath = p.get("path") or ""
|
|
1909
|
+
if not Path(ppath).is_dir():
|
|
1910
|
+
skipped.append({"path": ppath, "reason": "not accessible"})
|
|
1911
|
+
continue
|
|
1912
|
+
if not (Path(ppath) / ".c3").is_dir():
|
|
1913
|
+
skipped.append({"path": ppath, "reason": "not initialized"})
|
|
1914
|
+
continue
|
|
1915
|
+
try:
|
|
1916
|
+
if status_filter and status_filter != "all":
|
|
1917
|
+
rows = TaskStore(ppath).list_tasks(status=status_filter, limit=1000)
|
|
1918
|
+
else:
|
|
1919
|
+
rows = TaskStore(ppath).list_tasks(limit=1000)
|
|
1920
|
+
if status_filter != "all":
|
|
1921
|
+
rows = [t for t in rows if t.get("status") != "done"]
|
|
1922
|
+
except Exception as e:
|
|
1923
|
+
skipped.append({"path": ppath, "reason": str(e)})
|
|
1924
|
+
continue
|
|
1925
|
+
if not rows:
|
|
1926
|
+
continue
|
|
1927
|
+
proj_info = {"name": p.get("name"), "path": ppath}
|
|
1928
|
+
if p.get("parent_path"):
|
|
1929
|
+
proj_info["parent_path"] = p["parent_path"]
|
|
1930
|
+
for t in rows:
|
|
1931
|
+
t["project"] = proj_info
|
|
1932
|
+
tasks.extend(rows)
|
|
1933
|
+
by_project[ppath] = {"name": p.get("name"), "open": len(rows)}
|
|
1934
|
+
|
|
1935
|
+
# priority asc, due asc, updated desc (stable two-stage sort)
|
|
1936
|
+
tasks.sort(key=lambda t: t.get("updated_at") or "", reverse=True)
|
|
1937
|
+
tasks.sort(key=lambda t: (t.get("priority", "p2"), t.get("due_date") or "9999"))
|
|
1938
|
+
capped = len(tasks) > limit
|
|
1939
|
+
return jsonify({"projects_scanned": len(entries) - len(skipped),
|
|
1940
|
+
"skipped": skipped, "capped": capped,
|
|
1941
|
+
"tasks": tasks[:limit], "by_project": by_project})
|
|
1942
|
+
|
|
1943
|
+
|
|
1662
1944
|
@app.route("/api/projects/run-mcp", methods=["POST"])
|
|
1663
1945
|
def api_run_mcp():
|
|
1664
1946
|
data = request.get_json(force=True) or {}
|
|
@@ -17,6 +17,7 @@ function App() {
|
|
|
17
17
|
const [version, setVersion] = useState('');
|
|
18
18
|
const [projects, setProjects] = useState([]);
|
|
19
19
|
const [loaded, setLoaded] = useState(false);
|
|
20
|
+
const [mainView, setMainView] = useState('projects'); // projects | board
|
|
20
21
|
const [filter, setFilter] = useState('all'); // all | active | idle | tag:<x>
|
|
21
22
|
const [search, setSearch] = useState('');
|
|
22
23
|
const [view, setView] = useState('list'); // list | grid
|
|
@@ -43,6 +44,7 @@ function App() {
|
|
|
43
44
|
if (cfg.projects_view === 'grid') setView('grid');
|
|
44
45
|
if (cfg.sidebar_collapsed != null) setSidebarCollapsed(!!cfg.sidebar_collapsed);
|
|
45
46
|
if (cfg.sidebar_group) setFilter(cfg.sidebar_group);
|
|
47
|
+
if (cfg.main_view === 'board') setMainView('board');
|
|
46
48
|
} catch { }
|
|
47
49
|
try { const v = await api.get('/api/version'); setVersion(v.c3_version || ''); } catch { }
|
|
48
50
|
}, []);
|
|
@@ -68,6 +70,10 @@ function App() {
|
|
|
68
70
|
setSidebarCollapsed(c);
|
|
69
71
|
api.post('/api/hub/config', { sidebar_collapsed: c }).catch(() => { });
|
|
70
72
|
};
|
|
73
|
+
const changeMainView = (v) => {
|
|
74
|
+
setMainView(v);
|
|
75
|
+
api.post('/api/hub/config', { main_view: v }).catch(() => { });
|
|
76
|
+
};
|
|
71
77
|
|
|
72
78
|
// Keyboard: Ctrl/Cmd-K opens cross-project search, Esc closes overlays
|
|
73
79
|
useEffect(() => {
|
|
@@ -92,7 +98,7 @@ function App() {
|
|
|
92
98
|
return (
|
|
93
99
|
<div style={{ display: 'flex', flexDirection: 'column', height: '100%', background: T.bg, color: T.text }}>
|
|
94
100
|
<TopBar version={version} activeCount={activeCount} darkMode={darkMode}
|
|
95
|
-
hubConfig={hubConfig}
|
|
101
|
+
hubConfig={hubConfig} mainView={mainView} setMainView={changeMainView}
|
|
96
102
|
onToggleTheme={toggleTheme}
|
|
97
103
|
onOpenSettings={() => openModal('settings')}
|
|
98
104
|
onOpenSearch={() => setSearchOpen(true)}
|
|
@@ -104,13 +110,19 @@ function App() {
|
|
|
104
110
|
flex: 1, minWidth: 0, overflowY: 'auto', padding: '18px 22px',
|
|
105
111
|
display: 'flex', flexDirection: 'column', gap: 12,
|
|
106
112
|
}}>
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
113
|
+
{mainView === 'board' ? (
|
|
114
|
+
<TaskBoard projects={projects} onOpenDrill={openDrill} />
|
|
115
|
+
) : (
|
|
116
|
+
<React.Fragment>
|
|
117
|
+
<SummaryBar projects={projects} search={search} setSearch={setSearch}
|
|
118
|
+
view={view} setView={changeView} filter={filter} setFilter={changeFilter}
|
|
119
|
+
onUpdateAll={() => openModal('batch')}
|
|
120
|
+
onAddProject={() => openModal('add')} />
|
|
121
|
+
<ProjectTree projects={visible} allProjects={projects} view={view} loaded={loaded}
|
|
122
|
+
onChanged={loadProjects} onOpenDrill={openDrill} onOpenModal={openModal}
|
|
123
|
+
onOpenDrawer={setDrawerProject} />
|
|
124
|
+
</React.Fragment>
|
|
125
|
+
)}
|
|
114
126
|
</main>
|
|
115
127
|
</div>
|
|
116
128
|
{drawerProject &&
|
{code_context_control-2.44.1 → code_context_control-2.45.0}/cli/hub_ui/components/drill_panel.js
RENAMED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
const DRILL_PANEL_TABS = [
|
|
7
7
|
['overview', 'Overview'],
|
|
8
|
+
['tasks', 'Tasks'],
|
|
8
9
|
['memory', 'Memory'],
|
|
9
10
|
['ledger', 'Ledger'],
|
|
10
11
|
['sessions', 'Sessions'],
|
|
@@ -107,6 +108,7 @@ function DrillNeedsInit({ project, onReady }) {
|
|
|
107
108
|
function DrillPanel({ project, tab, setTab, onClose, onChanged, onOpenModal }) {
|
|
108
109
|
const renderTab = () => {
|
|
109
110
|
switch (tab) {
|
|
111
|
+
case 'tasks': return <DrillTasks project={project} onChanged={onChanged} />;
|
|
110
112
|
case 'memory': return <DrillMemory project={project} />;
|
|
111
113
|
case 'ledger': return <DrillLedger project={project} />;
|
|
112
114
|
case 'sessions': return <DrillSessions project={project} />;
|