code-context-control 2.52.0__tar.gz → 2.54.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.
Files changed (329) hide show
  1. {code_context_control-2.52.0 → code_context_control-2.54.0}/PKG-INFO +2 -2
  2. {code_context_control-2.52.0 → code_context_control-2.54.0}/README.md +1 -1
  3. {code_context_control-2.52.0 → code_context_control-2.54.0}/cli/c3.py +54 -17
  4. {code_context_control-2.52.0 → code_context_control-2.54.0}/cli/commands/parser.py +1 -0
  5. {code_context_control-2.52.0 → code_context_control-2.54.0}/cli/hub_server.py +151 -26
  6. {code_context_control-2.52.0 → code_context_control-2.54.0}/cli/hub_ui/components/task_board.js +94 -16
  7. {code_context_control-2.52.0 → code_context_control-2.54.0}/cli/mcp_server.py +27 -4
  8. code_context_control-2.54.0/cli/progress.py +49 -0
  9. {code_context_control-2.52.0 → code_context_control-2.54.0}/cli/server.py +104 -16
  10. {code_context_control-2.52.0 → code_context_control-2.54.0}/cli/tools/tasks.py +182 -9
  11. code_context_control-2.54.0/cli/ui/components/tasks.js +821 -0
  12. {code_context_control-2.52.0 → code_context_control-2.54.0}/cli/ui/pm_shared.js +72 -0
  13. {code_context_control-2.52.0 → code_context_control-2.54.0}/code_context_control.egg-info/PKG-INFO +2 -2
  14. {code_context_control-2.52.0 → code_context_control-2.54.0}/code_context_control.egg-info/SOURCES.txt +5 -0
  15. {code_context_control-2.52.0 → code_context_control-2.54.0}/pyproject.toml +1 -1
  16. {code_context_control-2.52.0 → code_context_control-2.54.0}/services/compressor.py +5 -13
  17. {code_context_control-2.52.0 → code_context_control-2.54.0}/services/doc_index.py +21 -17
  18. {code_context_control-2.52.0 → code_context_control-2.54.0}/services/embedding_index.py +49 -5
  19. {code_context_control-2.52.0 → code_context_control-2.54.0}/services/indexer.py +58 -21
  20. {code_context_control-2.52.0 → code_context_control-2.54.0}/services/protocol.py +37 -26
  21. {code_context_control-2.52.0 → code_context_control-2.54.0}/services/runtime.py +6 -0
  22. code_context_control-2.54.0/services/scanner.py +120 -0
  23. {code_context_control-2.52.0 → code_context_control-2.54.0}/services/subprojects.py +3 -1
  24. code_context_control-2.54.0/services/task_store.py +1108 -0
  25. code_context_control-2.54.0/services/time_tracker.py +285 -0
  26. code_context_control-2.54.0/tests/test_init_scan.py +195 -0
  27. {code_context_control-2.52.0 → code_context_control-2.54.0}/tests/test_pm_api.py +91 -0
  28. code_context_control-2.54.0/tests/test_task_store.py +509 -0
  29. {code_context_control-2.52.0 → code_context_control-2.54.0}/tests/test_task_tool.py +3 -1
  30. code_context_control-2.54.0/tests/test_time_tracker.py +115 -0
  31. {code_context_control-2.52.0 → code_context_control-2.54.0}/tests/test_windows_reliability.py +2 -1
  32. code_context_control-2.52.0/cli/ui/components/tasks.js +0 -287
  33. code_context_control-2.52.0/services/task_store.py +0 -578
  34. code_context_control-2.52.0/tests/test_task_store.py +0 -232
  35. {code_context_control-2.52.0 → code_context_control-2.54.0}/LICENSE +0 -0
  36. {code_context_control-2.52.0 → code_context_control-2.54.0}/cli/__init__.py +0 -0
  37. {code_context_control-2.52.0 → code_context_control-2.54.0}/cli/_hook_utils.py +0 -0
  38. {code_context_control-2.52.0 → code_context_control-2.54.0}/cli/commands/__init__.py +0 -0
  39. {code_context_control-2.52.0 → code_context_control-2.54.0}/cli/commands/common.py +0 -0
  40. {code_context_control-2.52.0 → code_context_control-2.54.0}/cli/docs.html +0 -0
  41. {code_context_control-2.52.0 → code_context_control-2.54.0}/cli/edits.html +0 -0
  42. {code_context_control-2.52.0 → code_context_control-2.54.0}/cli/guide/bitbucket.html +0 -0
  43. {code_context_control-2.52.0 → code_context_control-2.54.0}/cli/guide/getting-started.html +0 -0
  44. {code_context_control-2.52.0 → code_context_control-2.54.0}/cli/guide/index.html +0 -0
  45. {code_context_control-2.52.0 → code_context_control-2.54.0}/cli/guide/oracle.html +0 -0
  46. {code_context_control-2.52.0 → code_context_control-2.54.0}/cli/guide/shared.css +0 -0
  47. {code_context_control-2.52.0 → code_context_control-2.54.0}/cli/guide/tools.html +0 -0
  48. {code_context_control-2.52.0 → code_context_control-2.54.0}/cli/guide/workflow.html +0 -0
  49. {code_context_control-2.52.0 → code_context_control-2.54.0}/cli/hook_artifact.py +0 -0
  50. {code_context_control-2.52.0 → code_context_control-2.54.0}/cli/hook_auto_snapshot.py +0 -0
  51. {code_context_control-2.52.0 → code_context_control-2.54.0}/cli/hook_c3_signal.py +0 -0
  52. {code_context_control-2.52.0 → code_context_control-2.54.0}/cli/hook_c3read.py +0 -0
  53. {code_context_control-2.52.0 → code_context_control-2.54.0}/cli/hook_dispatch.py +0 -0
  54. {code_context_control-2.52.0 → code_context_control-2.54.0}/cli/hook_edit_ledger.py +0 -0
  55. {code_context_control-2.52.0 → code_context_control-2.54.0}/cli/hook_edit_unlock.py +0 -0
  56. {code_context_control-2.52.0 → code_context_control-2.54.0}/cli/hook_filter.py +0 -0
  57. {code_context_control-2.52.0 → code_context_control-2.54.0}/cli/hook_ghost_files.py +0 -0
  58. {code_context_control-2.52.0 → code_context_control-2.54.0}/cli/hook_pretool_enforce.py +0 -0
  59. {code_context_control-2.52.0 → code_context_control-2.54.0}/cli/hook_prompt_recall.py +0 -0
  60. {code_context_control-2.52.0 → code_context_control-2.54.0}/cli/hook_read.py +0 -0
  61. {code_context_control-2.52.0 → code_context_control-2.54.0}/cli/hook_session_stats.py +0 -0
  62. {code_context_control-2.52.0 → code_context_control-2.54.0}/cli/hook_terse_advisor.py +0 -0
  63. {code_context_control-2.52.0 → code_context_control-2.54.0}/cli/hub.html +0 -0
  64. {code_context_control-2.52.0 → code_context_control-2.54.0}/cli/hub_ui/app.js +0 -0
  65. {code_context_control-2.52.0 → code_context_control-2.54.0}/cli/hub_ui/components/add_project.js +0 -0
  66. {code_context_control-2.52.0 → code_context_control-2.54.0}/cli/hub_ui/components/config_editor.js +0 -0
  67. {code_context_control-2.52.0 → code_context_control-2.54.0}/cli/hub_ui/components/drill_artifacts.js +0 -0
  68. {code_context_control-2.52.0 → code_context_control-2.54.0}/cli/hub_ui/components/drill_health.js +0 -0
  69. {code_context_control-2.52.0 → code_context_control-2.54.0}/cli/hub_ui/components/drill_panel.js +0 -0
  70. {code_context_control-2.52.0 → code_context_control-2.54.0}/cli/hub_ui/components/drill_tasks.js +0 -0
  71. {code_context_control-2.52.0 → code_context_control-2.54.0}/cli/hub_ui/components/drill_views.js +0 -0
  72. {code_context_control-2.52.0 → code_context_control-2.54.0}/cli/hub_ui/components/global_search.js +0 -0
  73. {code_context_control-2.52.0 → code_context_control-2.54.0}/cli/hub_ui/components/mcp_manager.js +0 -0
  74. {code_context_control-2.52.0 → code_context_control-2.54.0}/cli/hub_ui/components/modals.js +0 -0
  75. {code_context_control-2.52.0 → code_context_control-2.54.0}/cli/hub_ui/components/project_card.js +0 -0
  76. {code_context_control-2.52.0 → code_context_control-2.54.0}/cli/hub_ui/components/project_tree.js +0 -0
  77. {code_context_control-2.52.0 → code_context_control-2.54.0}/cli/hub_ui/components/session_drawer.js +0 -0
  78. {code_context_control-2.52.0 → code_context_control-2.54.0}/cli/hub_ui/components/settings_modal.js +0 -0
  79. {code_context_control-2.52.0 → code_context_control-2.54.0}/cli/hub_ui/components/sidebar.js +0 -0
  80. {code_context_control-2.52.0 → code_context_control-2.54.0}/cli/hub_ui/components/summary_bar.js +0 -0
  81. {code_context_control-2.52.0 → code_context_control-2.54.0}/cli/hub_ui/components/toasts.js +0 -0
  82. {code_context_control-2.52.0 → code_context_control-2.54.0}/cli/hub_ui/components/topbar.js +0 -0
  83. {code_context_control-2.52.0 → code_context_control-2.54.0}/cli/hub_ui/state.js +0 -0
  84. {code_context_control-2.52.0 → code_context_control-2.54.0}/cli/hub_ui.html +0 -0
  85. {code_context_control-2.52.0 → code_context_control-2.54.0}/cli/mcp_proxy.py +0 -0
  86. {code_context_control-2.52.0 → code_context_control-2.54.0}/cli/tools/__init__.py +0 -0
  87. {code_context_control-2.52.0 → code_context_control-2.54.0}/cli/tools/_helpers.py +0 -0
  88. {code_context_control-2.52.0 → code_context_control-2.54.0}/cli/tools/agent.py +0 -0
  89. {code_context_control-2.52.0 → code_context_control-2.54.0}/cli/tools/artifacts.py +0 -0
  90. {code_context_control-2.52.0 → code_context_control-2.54.0}/cli/tools/bitbucket.py +0 -0
  91. {code_context_control-2.52.0 → code_context_control-2.54.0}/cli/tools/compress.py +0 -0
  92. {code_context_control-2.52.0 → code_context_control-2.54.0}/cli/tools/delegate.py +0 -0
  93. {code_context_control-2.52.0 → code_context_control-2.54.0}/cli/tools/edit.py +0 -0
  94. {code_context_control-2.52.0 → code_context_control-2.54.0}/cli/tools/edits.py +0 -0
  95. {code_context_control-2.52.0 → code_context_control-2.54.0}/cli/tools/federate.py +0 -0
  96. {code_context_control-2.52.0 → code_context_control-2.54.0}/cli/tools/filter.py +0 -0
  97. {code_context_control-2.52.0 → code_context_control-2.54.0}/cli/tools/impact.py +0 -0
  98. {code_context_control-2.52.0 → code_context_control-2.54.0}/cli/tools/memory.py +0 -0
  99. {code_context_control-2.52.0 → code_context_control-2.54.0}/cli/tools/project.py +0 -0
  100. {code_context_control-2.52.0 → code_context_control-2.54.0}/cli/tools/read.py +0 -0
  101. {code_context_control-2.52.0 → code_context_control-2.54.0}/cli/tools/search.py +0 -0
  102. {code_context_control-2.52.0 → code_context_control-2.54.0}/cli/tools/session.py +0 -0
  103. {code_context_control-2.52.0 → code_context_control-2.54.0}/cli/tools/shell.py +0 -0
  104. {code_context_control-2.52.0 → code_context_control-2.54.0}/cli/tools/status.py +0 -0
  105. {code_context_control-2.52.0 → code_context_control-2.54.0}/cli/tools/validate.py +0 -0
  106. {code_context_control-2.52.0 → code_context_control-2.54.0}/cli/ui/api.js +0 -0
  107. {code_context_control-2.52.0 → code_context_control-2.54.0}/cli/ui/app.js +0 -0
  108. {code_context_control-2.52.0 → code_context_control-2.54.0}/cli/ui/components/bitbucket.js +0 -0
  109. {code_context_control-2.52.0 → code_context_control-2.54.0}/cli/ui/components/chat.js +0 -0
  110. {code_context_control-2.52.0 → code_context_control-2.54.0}/cli/ui/components/dashboard.js +0 -0
  111. {code_context_control-2.52.0 → code_context_control-2.54.0}/cli/ui/components/edits.js +0 -0
  112. {code_context_control-2.52.0 → code_context_control-2.54.0}/cli/ui/components/instructions.js +0 -0
  113. {code_context_control-2.52.0 → code_context_control-2.54.0}/cli/ui/components/memory.js +0 -0
  114. {code_context_control-2.52.0 → code_context_control-2.54.0}/cli/ui/components/sessions.js +0 -0
  115. {code_context_control-2.52.0 → code_context_control-2.54.0}/cli/ui/components/settings.js +0 -0
  116. {code_context_control-2.52.0 → code_context_control-2.54.0}/cli/ui/components/sidebar.js +0 -0
  117. {code_context_control-2.52.0 → code_context_control-2.54.0}/cli/ui/icons.js +0 -0
  118. {code_context_control-2.52.0 → code_context_control-2.54.0}/cli/ui/shared.js +0 -0
  119. {code_context_control-2.52.0 → code_context_control-2.54.0}/cli/ui/theme.js +0 -0
  120. {code_context_control-2.52.0 → code_context_control-2.54.0}/cli/ui.html +0 -0
  121. {code_context_control-2.52.0 → code_context_control-2.54.0}/cli/ui_legacy.html +0 -0
  122. {code_context_control-2.52.0 → code_context_control-2.54.0}/cli/ui_nano.html +0 -0
  123. {code_context_control-2.52.0 → code_context_control-2.54.0}/code_context_control.egg-info/dependency_links.txt +0 -0
  124. {code_context_control-2.52.0 → code_context_control-2.54.0}/code_context_control.egg-info/entry_points.txt +0 -0
  125. {code_context_control-2.52.0 → code_context_control-2.54.0}/code_context_control.egg-info/requires.txt +0 -0
  126. {code_context_control-2.52.0 → code_context_control-2.54.0}/code_context_control.egg-info/top_level.txt +0 -0
  127. {code_context_control-2.52.0 → code_context_control-2.54.0}/core/__init__.py +0 -0
  128. {code_context_control-2.52.0 → code_context_control-2.54.0}/core/config.py +0 -0
  129. {code_context_control-2.52.0 → code_context_control-2.54.0}/core/ide.py +0 -0
  130. {code_context_control-2.52.0 → code_context_control-2.54.0}/core/mcp_toml.py +0 -0
  131. {code_context_control-2.52.0 → code_context_control-2.54.0}/core/web_security.py +0 -0
  132. {code_context_control-2.52.0 → code_context_control-2.54.0}/oracle/__init__.py +0 -0
  133. {code_context_control-2.52.0 → code_context_control-2.54.0}/oracle/config.py +0 -0
  134. {code_context_control-2.52.0 → code_context_control-2.54.0}/oracle/mcp_oracle.py +0 -0
  135. {code_context_control-2.52.0 → code_context_control-2.54.0}/oracle/oracle_server.py +0 -0
  136. {code_context_control-2.52.0 → code_context_control-2.54.0}/oracle/oracle_ui.html +0 -0
  137. {code_context_control-2.52.0 → code_context_control-2.54.0}/oracle/services/__init__.py +0 -0
  138. {code_context_control-2.52.0 → code_context_control-2.54.0}/oracle/services/activity_reporter.py +0 -0
  139. {code_context_control-2.52.0 → code_context_control-2.54.0}/oracle/services/api_auth.py +0 -0
  140. {code_context_control-2.52.0 → code_context_control-2.54.0}/oracle/services/c3_bridge.py +0 -0
  141. {code_context_control-2.52.0 → code_context_control-2.54.0}/oracle/services/chat_engine.py +0 -0
  142. {code_context_control-2.52.0 → code_context_control-2.54.0}/oracle/services/chat_store.py +0 -0
  143. {code_context_control-2.52.0 → code_context_control-2.54.0}/oracle/services/cross_memory.py +0 -0
  144. {code_context_control-2.52.0 → code_context_control-2.54.0}/oracle/services/federated_graph.py +0 -0
  145. {code_context_control-2.52.0 → code_context_control-2.54.0}/oracle/services/health_checker.py +0 -0
  146. {code_context_control-2.52.0 → code_context_control-2.54.0}/oracle/services/insight_engine.py +0 -0
  147. {code_context_control-2.52.0 → code_context_control-2.54.0}/oracle/services/local_session.py +0 -0
  148. {code_context_control-2.52.0 → code_context_control-2.54.0}/oracle/services/memory_reader.py +0 -0
  149. {code_context_control-2.52.0 → code_context_control-2.54.0}/oracle/services/memory_writer.py +0 -0
  150. {code_context_control-2.52.0 → code_context_control-2.54.0}/oracle/services/project_scanner.py +0 -0
  151. {code_context_control-2.52.0 → code_context_control-2.54.0}/oracle/services/review_agent.py +0 -0
  152. {code_context_control-2.52.0 → code_context_control-2.54.0}/oracle/services/tool_executor.py +0 -0
  153. {code_context_control-2.52.0 → code_context_control-2.54.0}/oracle/services/tool_registry.py +0 -0
  154. {code_context_control-2.52.0 → code_context_control-2.54.0}/oracle/ui/activity.js +0 -0
  155. {code_context_control-2.52.0 → code_context_control-2.54.0}/oracle/ui/agents.js +0 -0
  156. {code_context_control-2.52.0 → code_context_control-2.54.0}/oracle/ui/app.js +0 -0
  157. {code_context_control-2.52.0 → code_context_control-2.54.0}/oracle/ui/busy.js +0 -0
  158. {code_context_control-2.52.0 → code_context_control-2.54.0}/oracle/ui/chat/conversations.js +0 -0
  159. {code_context_control-2.52.0 → code_context_control-2.54.0}/oracle/ui/chat/input.js +0 -0
  160. {code_context_control-2.52.0 → code_context_control-2.54.0}/oracle/ui/chat/markdown.js +0 -0
  161. {code_context_control-2.52.0 → code_context_control-2.54.0}/oracle/ui/chat/send.js +0 -0
  162. {code_context_control-2.52.0 → code_context_control-2.54.0}/oracle/ui/chat/stream_renderer.js +0 -0
  163. {code_context_control-2.52.0 → code_context_control-2.54.0}/oracle/ui/chat/toolbar.js +0 -0
  164. {code_context_control-2.52.0 → code_context_control-2.54.0}/oracle/ui/core.js +0 -0
  165. {code_context_control-2.52.0 → code_context_control-2.54.0}/oracle/ui/crossgraph.js +0 -0
  166. {code_context_control-2.52.0 → code_context_control-2.54.0}/oracle/ui/header.js +0 -0
  167. {code_context_control-2.52.0 → code_context_control-2.54.0}/oracle/ui/insights.js +0 -0
  168. {code_context_control-2.52.0 → code_context_control-2.54.0}/oracle/ui/projects.js +0 -0
  169. {code_context_control-2.52.0 → code_context_control-2.54.0}/oracle/ui/settings.js +0 -0
  170. {code_context_control-2.52.0 → code_context_control-2.54.0}/oracle/ui/suggestions.js +0 -0
  171. {code_context_control-2.52.0 → code_context_control-2.54.0}/oracle/ui/theme_tabs.js +0 -0
  172. {code_context_control-2.52.0 → code_context_control-2.54.0}/services/__init__.py +0 -0
  173. {code_context_control-2.52.0 → code_context_control-2.54.0}/services/activity_log.py +0 -0
  174. {code_context_control-2.52.0 → code_context_control-2.54.0}/services/agent_base.py +0 -0
  175. {code_context_control-2.52.0 → code_context_control-2.54.0}/services/agents.py +0 -0
  176. {code_context_control-2.52.0 → code_context_control-2.54.0}/services/artifact_defs.py +0 -0
  177. {code_context_control-2.52.0 → code_context_control-2.54.0}/services/artifact_store.py +0 -0
  178. {code_context_control-2.52.0 → code_context_control-2.54.0}/services/auto_memory.py +0 -0
  179. {code_context_control-2.52.0 → code_context_control-2.54.0}/services/bench/__init__.py +0 -0
  180. {code_context_control-2.52.0 → code_context_control-2.54.0}/services/bench/external/__init__.py +0 -0
  181. {code_context_control-2.52.0 → code_context_control-2.54.0}/services/bench/external/aider_polyglot.py +0 -0
  182. {code_context_control-2.52.0 → code_context_control-2.54.0}/services/bench/external/swe_bench.py +0 -0
  183. {code_context_control-2.52.0 → code_context_control-2.54.0}/services/benchmark_dashboard.py +0 -0
  184. {code_context_control-2.52.0 → code_context_control-2.54.0}/services/bitbucket_client.py +0 -0
  185. {code_context_control-2.52.0 → code_context_control-2.54.0}/services/bitbucket_credentials.py +0 -0
  186. {code_context_control-2.52.0 → code_context_control-2.54.0}/services/circuit_breaker.py +0 -0
  187. {code_context_control-2.52.0 → code_context_control-2.54.0}/services/claude_md.py +0 -0
  188. {code_context_control-2.52.0 → code_context_control-2.54.0}/services/context_snapshot.py +0 -0
  189. {code_context_control-2.52.0 → code_context_control-2.54.0}/services/conversation_store.py +0 -0
  190. {code_context_control-2.52.0 → code_context_control-2.54.0}/services/e2e_benchmark.py +0 -0
  191. {code_context_control-2.52.0 → code_context_control-2.54.0}/services/e2e_evaluator.py +0 -0
  192. {code_context_control-2.52.0 → code_context_control-2.54.0}/services/e2e_tasks.py +0 -0
  193. {code_context_control-2.52.0 → code_context_control-2.54.0}/services/edit_ledger.py +0 -0
  194. {code_context_control-2.52.0 → code_context_control-2.54.0}/services/error_reporting.py +0 -0
  195. {code_context_control-2.52.0 → code_context_control-2.54.0}/services/file_memory.py +0 -0
  196. {code_context_control-2.52.0 → code_context_control-2.54.0}/services/git_context.py +0 -0
  197. {code_context_control-2.52.0 → code_context_control-2.54.0}/services/hub_service.py +0 -0
  198. {code_context_control-2.52.0 → code_context_control-2.54.0}/services/memory.py +0 -0
  199. {code_context_control-2.52.0 → code_context_control-2.54.0}/services/memory_consolidator.py +0 -0
  200. {code_context_control-2.52.0 → code_context_control-2.54.0}/services/memory_distiller.py +0 -0
  201. {code_context_control-2.52.0 → code_context_control-2.54.0}/services/memory_graph.py +0 -0
  202. {code_context_control-2.52.0 → code_context_control-2.54.0}/services/memory_grounder.py +0 -0
  203. {code_context_control-2.52.0 → code_context_control-2.54.0}/services/memory_queue.py +0 -0
  204. {code_context_control-2.52.0 → code_context_control-2.54.0}/services/memory_scorer.py +0 -0
  205. {code_context_control-2.52.0 → code_context_control-2.54.0}/services/metrics.py +0 -0
  206. {code_context_control-2.52.0 → code_context_control-2.54.0}/services/notifications.py +0 -0
  207. {code_context_control-2.52.0 → code_context_control-2.54.0}/services/ollama_bridge.py +0 -0
  208. {code_context_control-2.52.0 → code_context_control-2.54.0}/services/ollama_client.py +0 -0
  209. {code_context_control-2.52.0 → code_context_control-2.54.0}/services/ollama_credentials.py +0 -0
  210. {code_context_control-2.52.0 → code_context_control-2.54.0}/services/output_filter.py +0 -0
  211. {code_context_control-2.52.0 → code_context_control-2.54.0}/services/parser.py +0 -0
  212. {code_context_control-2.52.0 → code_context_control-2.54.0}/services/project_manager.py +0 -0
  213. {code_context_control-2.52.0 → code_context_control-2.54.0}/services/project_runtime.py +0 -0
  214. {code_context_control-2.52.0 → code_context_control-2.54.0}/services/proxy_state.py +0 -0
  215. {code_context_control-2.52.0 → code_context_control-2.54.0}/services/retention.py +0 -0
  216. {code_context_control-2.52.0 → code_context_control-2.54.0}/services/retrieval_broker.py +0 -0
  217. {code_context_control-2.52.0 → code_context_control-2.54.0}/services/router.py +0 -0
  218. {code_context_control-2.52.0 → code_context_control-2.54.0}/services/session_benchmark.py +0 -0
  219. {code_context_control-2.52.0 → code_context_control-2.54.0}/services/session_manager.py +0 -0
  220. {code_context_control-2.52.0 → code_context_control-2.54.0}/services/session_preloader.py +0 -0
  221. {code_context_control-2.52.0 → code_context_control-2.54.0}/services/telemetry.py +0 -0
  222. {code_context_control-2.52.0 → code_context_control-2.54.0}/services/text_index.py +0 -0
  223. {code_context_control-2.52.0 → code_context_control-2.54.0}/services/tool_classifier.py +0 -0
  224. {code_context_control-2.52.0 → code_context_control-2.54.0}/services/transcript_index.py +0 -0
  225. {code_context_control-2.52.0 → code_context_control-2.54.0}/services/validation_cache.py +0 -0
  226. {code_context_control-2.52.0 → code_context_control-2.54.0}/services/vector_store.py +0 -0
  227. {code_context_control-2.52.0 → code_context_control-2.54.0}/services/watcher.py +0 -0
  228. {code_context_control-2.52.0 → code_context_control-2.54.0}/services/win_subprocess.py +0 -0
  229. {code_context_control-2.52.0 → code_context_control-2.54.0}/setup.cfg +0 -0
  230. {code_context_control-2.52.0 → code_context_control-2.54.0}/tests/test_activity_reporter.py +0 -0
  231. {code_context_control-2.52.0 → code_context_control-2.54.0}/tests/test_aider_polyglot.py +0 -0
  232. {code_context_control-2.52.0 → code_context_control-2.54.0}/tests/test_antigravity_transition.py +0 -0
  233. {code_context_control-2.52.0 → code_context_control-2.54.0}/tests/test_artifact_store.py +0 -0
  234. {code_context_control-2.52.0 → code_context_control-2.54.0}/tests/test_artifact_tool.py +0 -0
  235. {code_context_control-2.52.0 → code_context_control-2.54.0}/tests/test_bitbucket_cli_smoke.py +0 -0
  236. {code_context_control-2.52.0 → code_context_control-2.54.0}/tests/test_bitbucket_client.py +0 -0
  237. {code_context_control-2.52.0 → code_context_control-2.54.0}/tests/test_bitbucket_config_fallback.py +0 -0
  238. {code_context_control-2.52.0 → code_context_control-2.54.0}/tests/test_bitbucket_credentials.py +0 -0
  239. {code_context_control-2.52.0 → code_context_control-2.54.0}/tests/test_bitbucket_tool.py +0 -0
  240. {code_context_control-2.52.0 → code_context_control-2.54.0}/tests/test_c3_bridge_project_artifacts.py +0 -0
  241. {code_context_control-2.52.0 → code_context_control-2.54.0}/tests/test_c3_shell.py +0 -0
  242. {code_context_control-2.52.0 → code_context_control-2.54.0}/tests/test_circuit_breaker.py +0 -0
  243. {code_context_control-2.52.0 → code_context_control-2.54.0}/tests/test_claude_md_merge.py +0 -0
  244. {code_context_control-2.52.0 → code_context_control-2.54.0}/tests/test_cli_smoke.py +0 -0
  245. {code_context_control-2.52.0 → code_context_control-2.54.0}/tests/test_compressor_large_file.py +0 -0
  246. {code_context_control-2.52.0 → code_context_control-2.54.0}/tests/test_delegate_cascade.py +0 -0
  247. {code_context_control-2.52.0 → code_context_control-2.54.0}/tests/test_e2e_benchmark.py +0 -0
  248. {code_context_control-2.52.0 → code_context_control-2.54.0}/tests/test_edit_ledger_hook.py +0 -0
  249. {code_context_control-2.52.0 → code_context_control-2.54.0}/tests/test_edit_normalization.py +0 -0
  250. {code_context_control-2.52.0 → code_context_control-2.54.0}/tests/test_enforcement_flip.py +0 -0
  251. {code_context_control-2.52.0 → code_context_control-2.54.0}/tests/test_federated_graph.py +0 -0
  252. {code_context_control-2.52.0 → code_context_control-2.54.0}/tests/test_filter_backoff.py +0 -0
  253. {code_context_control-2.52.0 → code_context_control-2.54.0}/tests/test_ghost_files.py +0 -0
  254. {code_context_control-2.52.0 → code_context_control-2.54.0}/tests/test_ghost_generation.py +0 -0
  255. {code_context_control-2.52.0 → code_context_control-2.54.0}/tests/test_git_branch_awareness.py +0 -0
  256. {code_context_control-2.52.0 → code_context_control-2.54.0}/tests/test_hook_dispatch.py +0 -0
  257. {code_context_control-2.52.0 → code_context_control-2.54.0}/tests/test_hook_pretool_enforce.py +0 -0
  258. {code_context_control-2.52.0 → code_context_control-2.54.0}/tests/test_hook_prompt_recall.py +0 -0
  259. {code_context_control-2.52.0 → code_context_control-2.54.0}/tests/test_hook_smoke.py +0 -0
  260. {code_context_control-2.52.0 → code_context_control-2.54.0}/tests/test_hook_state.py +0 -0
  261. {code_context_control-2.52.0 → code_context_control-2.54.0}/tests/test_hook_utf8_stdio.py +0 -0
  262. {code_context_control-2.52.0 → code_context_control-2.54.0}/tests/test_hub_inspect_api.py +0 -0
  263. {code_context_control-2.52.0 → code_context_control-2.54.0}/tests/test_hub_server_smoke.py +0 -0
  264. {code_context_control-2.52.0 → code_context_control-2.54.0}/tests/test_install_mcp_entrypoint.py +0 -0
  265. {code_context_control-2.52.0 → code_context_control-2.54.0}/tests/test_lazy_store_init.py +0 -0
  266. {code_context_control-2.52.0 → code_context_control-2.54.0}/tests/test_mcp_host_guard.py +0 -0
  267. {code_context_control-2.52.0 → code_context_control-2.54.0}/tests/test_mcp_memory_timeout.py +0 -0
  268. {code_context_control-2.52.0 → code_context_control-2.54.0}/tests/test_mcp_server_smoke.py +0 -0
  269. {code_context_control-2.52.0 → code_context_control-2.54.0}/tests/test_mcp_toml.py +0 -0
  270. {code_context_control-2.52.0 → code_context_control-2.54.0}/tests/test_memory_distiller.py +0 -0
  271. {code_context_control-2.52.0 → code_context_control-2.54.0}/tests/test_memory_graph_api.py +0 -0
  272. {code_context_control-2.52.0 → code_context_control-2.54.0}/tests/test_memory_queue.py +0 -0
  273. {code_context_control-2.52.0 → code_context_control-2.54.0}/tests/test_memory_system.py +0 -0
  274. {code_context_control-2.52.0 → code_context_control-2.54.0}/tests/test_notification_dedup.py +0 -0
  275. {code_context_control-2.52.0 → code_context_control-2.54.0}/tests/test_notification_discipline.py +0 -0
  276. {code_context_control-2.52.0 → code_context_control-2.54.0}/tests/test_ollama_credentials.py +0 -0
  277. {code_context_control-2.52.0 → code_context_control-2.54.0}/tests/test_oracle_api_auth.py +0 -0
  278. {code_context_control-2.52.0 → code_context_control-2.54.0}/tests/test_oracle_apikey_api.py +0 -0
  279. {code_context_control-2.52.0 → code_context_control-2.54.0}/tests/test_oracle_c3_bridge.py +0 -0
  280. {code_context_control-2.52.0 → code_context_control-2.54.0}/tests/test_oracle_chat_engine.py +0 -0
  281. {code_context_control-2.52.0 → code_context_control-2.54.0}/tests/test_oracle_discovery_api.py +0 -0
  282. {code_context_control-2.52.0 → code_context_control-2.54.0}/tests/test_oracle_local_auth.py +0 -0
  283. {code_context_control-2.52.0 → code_context_control-2.54.0}/tests/test_oracle_ollama_bridge.py +0 -0
  284. {code_context_control-2.52.0 → code_context_control-2.54.0}/tests/test_oracle_scanner_cache.py +0 -0
  285. {code_context_control-2.52.0 → code_context_control-2.54.0}/tests/test_oracle_security_fixes.py +0 -0
  286. {code_context_control-2.52.0 → code_context_control-2.54.0}/tests/test_oracle_subproject_awareness.py +0 -0
  287. {code_context_control-2.52.0 → code_context_control-2.54.0}/tests/test_oracle_ui_bundle.py +0 -0
  288. {code_context_control-2.52.0 → code_context_control-2.54.0}/tests/test_output_filter.py +0 -0
  289. {code_context_control-2.52.0 → code_context_control-2.54.0}/tests/test_permissions.py +0 -0
  290. {code_context_control-2.52.0 → code_context_control-2.54.0}/tests/test_project_manager.py +0 -0
  291. {code_context_control-2.52.0 → code_context_control-2.54.0}/tests/test_project_manager_merge.py +0 -0
  292. {code_context_control-2.52.0 → code_context_control-2.54.0}/tests/test_project_tool.py +0 -0
  293. {code_context_control-2.52.0 → code_context_control-2.54.0}/tests/test_read_coercion.py +0 -0
  294. {code_context_control-2.52.0 → code_context_control-2.54.0}/tests/test_read_edit_parity.py +0 -0
  295. {code_context_control-2.52.0 → code_context_control-2.54.0}/tests/test_related_facts.py +0 -0
  296. {code_context_control-2.52.0 → code_context_control-2.54.0}/tests/test_response_boilerplate.py +0 -0
  297. {code_context_control-2.52.0 → code_context_control-2.54.0}/tests/test_retention.py +0 -0
  298. {code_context_control-2.52.0 → code_context_control-2.54.0}/tests/test_review_digest.py +0 -0
  299. {code_context_control-2.52.0 → code_context_control-2.54.0}/tests/test_service_durability.py +0 -0
  300. {code_context_control-2.52.0 → code_context_control-2.54.0}/tests/test_session_benchmark.py +0 -0
  301. {code_context_control-2.52.0 → code_context_control-2.54.0}/tests/test_session_budget.py +0 -0
  302. {code_context_control-2.52.0 → code_context_control-2.54.0}/tests/test_shell_robustness.py +0 -0
  303. {code_context_control-2.52.0 → code_context_control-2.54.0}/tests/test_subproject_exclusion.py +0 -0
  304. {code_context_control-2.52.0 → code_context_control-2.54.0}/tests/test_subproject_federation.py +0 -0
  305. {code_context_control-2.52.0 → code_context_control-2.54.0}/tests/test_subprojects.py +0 -0
  306. {code_context_control-2.52.0 → code_context_control-2.54.0}/tests/test_swe_bench.py +0 -0
  307. {code_context_control-2.52.0 → code_context_control-2.54.0}/tests/test_token_telemetry.py +0 -0
  308. {code_context_control-2.52.0 → code_context_control-2.54.0}/tests/test_tool_registry.py +0 -0
  309. {code_context_control-2.52.0 → code_context_control-2.54.0}/tests/test_upgrade_and_version.py +0 -0
  310. {code_context_control-2.52.0 → code_context_control-2.54.0}/tests/test_validate.py +0 -0
  311. {code_context_control-2.52.0 → code_context_control-2.54.0}/tests/test_web_security.py +0 -0
  312. {code_context_control-2.52.0 → code_context_control-2.54.0}/tui/__init__.py +0 -0
  313. {code_context_control-2.52.0 → code_context_control-2.54.0}/tui/backend.py +0 -0
  314. {code_context_control-2.52.0 → code_context_control-2.54.0}/tui/main.py +0 -0
  315. {code_context_control-2.52.0 → code_context_control-2.54.0}/tui/screens/__init__.py +0 -0
  316. {code_context_control-2.52.0 → code_context_control-2.54.0}/tui/screens/benchmark_view.py +0 -0
  317. {code_context_control-2.52.0 → code_context_control-2.54.0}/tui/screens/claudemd_view.py +0 -0
  318. {code_context_control-2.52.0 → code_context_control-2.54.0}/tui/screens/compress_view.py +0 -0
  319. {code_context_control-2.52.0 → code_context_control-2.54.0}/tui/screens/index_view.py +0 -0
  320. {code_context_control-2.52.0 → code_context_control-2.54.0}/tui/screens/init_view.py +0 -0
  321. {code_context_control-2.52.0 → code_context_control-2.54.0}/tui/screens/mcp_view.py +0 -0
  322. {code_context_control-2.52.0 → code_context_control-2.54.0}/tui/screens/optimize_view.py +0 -0
  323. {code_context_control-2.52.0 → code_context_control-2.54.0}/tui/screens/pipe_view.py +0 -0
  324. {code_context_control-2.52.0 → code_context_control-2.54.0}/tui/screens/projects_view.py +0 -0
  325. {code_context_control-2.52.0 → code_context_control-2.54.0}/tui/screens/search_view.py +0 -0
  326. {code_context_control-2.52.0 → code_context_control-2.54.0}/tui/screens/session_view.py +0 -0
  327. {code_context_control-2.52.0 → code_context_control-2.54.0}/tui/screens/stats.py +0 -0
  328. {code_context_control-2.52.0 → code_context_control-2.54.0}/tui/screens/ui_view.py +0 -0
  329. {code_context_control-2.52.0 → code_context_control-2.54.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.52.0
3
+ Version: 2.54.0
4
4
  Summary: Local code-intelligence layer for AI coding tools (Claude Code, Codex, Copilot, Cursor, Antigravity). 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
@@ -275,7 +275,7 @@ C3 exposes 18 tools as a native MCP server. Your IDE calls them directly:
275
275
  | `c3_edits` | Edit-ledger queries + version diffs + restore points + per-branch filter |
276
276
  | `c3_bitbucket` | Bitbucket Data Center integration — PRs, branches, builds, repo admin (v2.30.0) |
277
277
  | `c3_project` | Cross-project — discover & operate on other c3-installed projects; guarded writes (v2.31.0) |
278
- | `c3_task` | Durable per-project tasks, milestones, and decision notes (v2.45.0) |
278
+ | `c3_task` | Durable per-project PM — tasks with dependencies & subtasks, milestones, decision notes, event history, health reports, and auto+manual time tracking (v2.53.0) |
279
279
  | `c3_artifacts` | Agent-config tracking — version history, diff & restore for CLAUDE.md, settings/hooks, MCP configs, skills (v2.46.0) |
280
280
 
281
281
  On Windows, `c3_shell` uses Git Bash when available. Git Bash does not bundle
@@ -212,7 +212,7 @@ C3 exposes 18 tools as a native MCP server. Your IDE calls them directly:
212
212
  | `c3_edits` | Edit-ledger queries + version diffs + restore points + per-branch filter |
213
213
  | `c3_bitbucket` | Bitbucket Data Center integration — PRs, branches, builds, repo admin (v2.30.0) |
214
214
  | `c3_project` | Cross-project — discover & operate on other c3-installed projects; guarded writes (v2.31.0) |
215
- | `c3_task` | Durable per-project tasks, milestones, and decision notes (v2.45.0) |
215
+ | `c3_task` | Durable per-project PM — tasks with dependencies & subtasks, milestones, decision notes, event history, health reports, and auto+manual time tracking (v2.53.0) |
216
216
  | `c3_artifacts` | Agent-config tracking — version history, diff & restore for CLAUDE.md, settings/hooks, MCP configs, skills (v2.46.0) |
217
217
 
218
218
  On Windows, `c3_shell` uses Git Bash when available. Git Bash does not bundle
@@ -92,7 +92,7 @@ console = Console() if HAS_RICH else None
92
92
  # Config
93
93
  CONFIG_DIR = ".c3"
94
94
  CONFIG_FILE = ".c3/config.json"
95
- __version__ = "2.52.0"
95
+ __version__ = "2.54.0"
96
96
 
97
97
 
98
98
  def _command_deps() -> CommandDeps:
@@ -165,6 +165,7 @@ def _build_init_config(project_path: str) -> dict:
165
165
  "project_path": project_path,
166
166
  "version": __version__,
167
167
  "index_auto_update": True,
168
+ "index_max_files": 2000,
168
169
  "compression_mode": "smart",
169
170
  "mcp": {"mode": "direct"},
170
171
  "hybrid": deepcopy(HYBRID_DEFAULTS),
@@ -890,7 +891,7 @@ def _parse_cli_ide_arg(value: str) -> str:
890
891
  return normalized
891
892
 
892
893
 
893
- def _do_init(project_path: str, ide_name: str = None):
894
+ def _do_init(project_path: str, ide_name: str = None, no_embed: bool = False):
894
895
  """Run the core init steps (shared by new install and re-init after clear/reset)."""
895
896
  config = _build_init_config(project_path)
896
897
  save_config(config, project_path)
@@ -898,10 +899,27 @@ def _do_init(project_path: str, ide_name: str = None):
898
899
  for subdir in _C3_INIT_SUBDIRS:
899
900
  (Path(project_path) / CONFIG_DIR / subdir).mkdir(parents=True, exist_ok=True)
900
901
 
902
+ import time as _t
903
+
904
+ from cli.progress import ProgressLine
905
+
901
906
  print("Building code index...")
907
+ _prog = ProgressLine()
908
+ _t0 = _t.perf_counter()
902
909
  indexer = CodeIndex(project_path)
903
- result = indexer.build_index()
904
- print(f" Indexed {result['files_indexed']} files, {result['chunks_created']} chunks")
910
+ result = indexer.build_index(
911
+ on_progress=lambda entries, files, chunks: _prog.update(
912
+ f" scanning: {entries:,} entries | {files:,} files | {chunks:,} chunks"))
913
+ _prog.done()
914
+ entries = result.get("entries_scanned", 0)
915
+ print(f" Indexed {result['files_indexed']} files, {result['chunks_created']} chunks "
916
+ f"in {_t.perf_counter() - _t0:.1f}s ({entries:,} entries scanned)")
917
+ capped = result.get("files_capped", 0)
918
+ if capped:
919
+ total = result["files_indexed"] + capped
920
+ print(f" [!] Indexed {result['files_indexed']} of {total} candidate files "
921
+ f"(cap: index_max_files={result.get('max_files')}).")
922
+ print(" Raise index_max_files in .c3/config.json for full coverage.")
905
923
 
906
924
  # Build embedding index if Ollama is available (non-blocking on failure)
907
925
  try:
@@ -912,13 +930,24 @@ def _do_init(project_path: str, ide_name: str = None):
912
930
  ollama = OllamaClient(ollama_url)
913
931
  embed_model = config.get("embed_model", "nomic-embed-text")
914
932
  ei = EmbeddingIndex(project_path, ollama, embed_model=embed_model)
915
- if ei.ready:
933
+ if no_embed:
934
+ print(" Embedding index skipped (--no-embed)")
935
+ elif ei.probe()["ready"]:
936
+ # probe() initializes the lazy backends; checking .ready on a
937
+ # fresh instance is always False and silently skipped the build.
916
938
  print("Building embedding index...")
917
- ei_result = ei.build(indexer)
939
+ _t0 = _t.perf_counter()
940
+ _eprog = ProgressLine()
941
+ ei_result = ei.build(
942
+ indexer,
943
+ on_progress=lambda done, total, chunks: _eprog.update(
944
+ f" embedding: file {done}/{total} | {chunks:,} chunks"))
945
+ _eprog.done()
918
946
  print(f" Embedded {ei_result.get('chunks_embedded', 0)} chunks "
919
- f"({ei_result.get('files_processed', 0)} files)")
947
+ f"({ei_result.get('files_processed', 0)} files) "
948
+ f"in {_t.perf_counter() - _t0:.1f}s")
920
949
  else:
921
- print(" Embedding index skipped (Ollama not available or model not pulled)")
950
+ print(f" Embedding index skipped ({ei.unavailable_reason()})")
922
951
  except Exception:
923
952
  _log.debug("Embedding index build failed", exc_info=True)
924
953
 
@@ -926,15 +955,22 @@ def _do_init(project_path: str, ide_name: str = None):
926
955
  try:
927
956
  from services.doc_index import DocIndex
928
957
  print("Building doc index...")
958
+ _t0 = _t.perf_counter()
959
+ _dprog = ProgressLine()
929
960
  di = DocIndex(project_path)
930
- di_result = di.build()
931
- print(f" Indexed {di_result['docs_indexed']} docs, {di_result['chunks_created']} chunks")
961
+ di_result = di.build(
962
+ on_progress=lambda done, total: _dprog.update(
963
+ f" docs: {done}/{total}"))
964
+ _dprog.done()
965
+ print(f" Indexed {di_result['docs_indexed']} docs, "
966
+ f"{di_result['chunks_created']} chunks in {_t.perf_counter() - _t0:.1f}s")
932
967
  except Exception:
933
968
  _log.debug("Doc index build failed", exc_info=True)
934
969
 
935
970
  print("Building compression dictionary...")
936
971
  protocol = CompressionProtocol(project_path)
937
- new_terms = protocol.build_project_dictionary()
972
+ # Mine the in-memory index instead of re-reading the whole tree.
973
+ new_terms = protocol.build_project_dictionary(code_index=indexer)
938
974
  print(f" Added {len(new_terms)} project-specific terms")
939
975
 
940
976
  from core.ide import detect_ide, load_ide_config
@@ -966,11 +1002,12 @@ def cmd_init(args):
966
1002
  if requested_ide != "auto":
967
1003
  requested_ide = normalize_ide_name(requested_ide)
968
1004
  git_requested = getattr(args, "git", False)
1005
+ no_embed = bool(getattr(args, "no_embed", False))
969
1006
 
970
1007
  # ── Brand-new install ──────────────────────────────────────
971
1008
  if not c3_dir.exists() or not (c3_dir / "config.json").exists():
972
1009
  print_header(f"Initializing C3 for: {project_path}")
973
- _do_init(project_path, ide_name=requested_ide)
1010
+ _do_init(project_path, ide_name=requested_ide, no_embed=no_embed)
974
1011
  try:
975
1012
  from services.project_manager import ProjectManager
976
1013
  ProjectManager().add_project(project_path)
@@ -1123,7 +1160,7 @@ def cmd_init(args):
1123
1160
  ti_manifest = c3_dir / "transcript_index" / "manifest.json"
1124
1161
  if ti_manifest.exists():
1125
1162
  ti_manifest.write_text("{}", encoding="utf-8")
1126
- _do_init(project_path, ide_name=requested_ide)
1163
+ _do_init(project_path, ide_name=requested_ide, no_embed=no_embed)
1127
1164
  if git_requested:
1128
1165
  _init_local_git_repo(project_path)
1129
1166
  _run_install_mcp(project_path, requested_ide, mcp_mode=getattr(args, "mcp_mode", "direct"), banner="Updating MCP tools...")
@@ -1152,7 +1189,7 @@ def cmd_init(args):
1152
1189
  # ── Non-interactive (--force) ──────────────────────────────
1153
1190
  if getattr(args, "force", False):
1154
1191
  print("\n[--force] Applying update...")
1155
- _do_init(project_path, ide_name=requested_ide)
1192
+ _do_init(project_path, ide_name=requested_ide, no_embed=no_embed)
1156
1193
  if git_requested:
1157
1194
  _init_local_git_repo(project_path)
1158
1195
  _run_install_mcp(project_path, requested_ide, mcp_mode=getattr(args, "mcp_mode", "direct"), banner="Updating MCP tools...")
@@ -1176,7 +1213,7 @@ def cmd_init(args):
1176
1213
 
1177
1214
  if selected.startswith("Update"):
1178
1215
  print()
1179
- _do_init(project_path, ide_name=requested_ide)
1216
+ _do_init(project_path, ide_name=requested_ide, no_embed=no_embed)
1180
1217
  if git_requested:
1181
1218
  _init_local_git_repo(project_path)
1182
1219
  _prompt_install_mcp(project_path, requested_ide, default_mode=getattr(args, "mcp_mode", "direct"), banner="Updating MCP tools...")
@@ -1192,7 +1229,7 @@ def cmd_init(args):
1192
1229
  shutil.rmtree(target)
1193
1230
  print(f" Removed .c3/{subdir}/")
1194
1231
  print()
1195
- _do_init(project_path, ide_name=requested_ide)
1232
+ _do_init(project_path, ide_name=requested_ide, no_embed=no_embed)
1196
1233
  if git_requested:
1197
1234
  _init_local_git_repo(project_path)
1198
1235
  _prompt_install_mcp(project_path, requested_ide, default_mode=getattr(args, "mcp_mode", "direct"), banner="Updating MCP tools...")
@@ -1209,7 +1246,7 @@ def cmd_init(args):
1209
1246
  shutil.rmtree(c3_dir)
1210
1247
  print(" Deleted .c3/")
1211
1248
  print()
1212
- _do_init(project_path, ide_name=requested_ide)
1249
+ _do_init(project_path, ide_name=requested_ide, no_embed=no_embed)
1213
1250
  if git_requested:
1214
1251
  _init_local_git_repo(project_path)
1215
1252
  _prompt_install_mcp(project_path, requested_ide, default_mode=getattr(args, "mcp_mode", "direct"), banner="Re-installing MCP tools...")
@@ -24,6 +24,7 @@ def build_parser(version: str, parse_cli_ide_arg):
24
24
  p_init.add_argument("--ide", default="auto", type=parse_cli_ide_arg, metavar="{auto,claude,vscode,cursor,codex,antigravity}", help="Target IDE for MCP config (default: auto-detect)")
25
25
  p_init.add_argument("--mcp-mode", choices=["direct", "proxy"], default="direct", help="Default MCP mode if install is selected during init (default: direct)")
26
26
  p_init.add_argument("--git", action="store_true", help="Initialize a local Git repository during init/update")
27
+ p_init.add_argument("--no-embed", action="store_true", help="Skip building the semantic embedding index during init")
27
28
  p_init.add_argument("--permissions", choices=["read-only", "c3-strict", "standard", "permissive"], default=None, help="Apply Claude Code permission tier (Claude Code only, used with --force)")
28
29
  p_init.add_argument("--include-mcp-wildcard", action="store_true", help="Add mcp__* wildcard so non-C3 MCP servers don't prompt per-call")
29
30
 
@@ -1027,8 +1027,10 @@ def api_run_component():
1027
1027
  ollama = OllamaClient(ollama_url)
1028
1028
  embed_model = cfg.get("embed_model", "nomic-embed-text")
1029
1029
  ei = EmbeddingIndex(resolved, ollama, embed_model=embed_model)
1030
- if not ei.ready:
1031
- return jsonify({"success": True, "output": "Embedding index skipped (Ollama not available or model not pulled)."})
1030
+ # probe() initializes lazy backends; a fresh instance's .ready
1031
+ # is always False and would skip the build unconditionally.
1032
+ if not ei.probe()["ready"]:
1033
+ return jsonify({"success": True, "output": f"Embedding index skipped ({ei.unavailable_reason()})."})
1032
1034
  indexer = CodeIndex(resolved)
1033
1035
  if not indexer.chunks:
1034
1036
  indexer._load_index()
@@ -1770,21 +1772,20 @@ def api_pm_task():
1770
1772
  task_id = (data.get("id") or "").strip()
1771
1773
  if not task_id:
1772
1774
  return jsonify({"error": "id is required"}), 400
1773
- res = None
1774
- fields = data.get("fields") or {}
1775
- if fields:
1776
- res = store.update_task(task_id, **fields)
1775
+ if data.get("restore"):
1776
+ res = store.restore_task(task_id, actor="hub")
1777
1777
  if "error" in res:
1778
1778
  return jsonify(res), 400
1779
- move = data.get("move") or {}
1780
- if move:
1781
- res = store.move_task(task_id, status=move.get("status"),
1782
- before_id=move.get("before_id"),
1783
- after_id=move.get("after_id"))
1784
- if "error" in res:
1785
- return jsonify(res), 400
1786
- if res is None:
1779
+ _pm_audit(resolved, "task", "restore", res["id"])
1780
+ return jsonify({"updated": True, "task": res})
1781
+ if not (data.get("fields") or data.get("move")):
1787
1782
  return jsonify({"error": "fields or move required"}), 400
1783
+ res = store.mutate_task(task_id, fields=data.get("fields"),
1784
+ move=data.get("move"),
1785
+ expected_rev=data.get("expected_rev"),
1786
+ actor="hub")
1787
+ if "error" in res:
1788
+ return jsonify(res), 409 if res.get("code") == "rev_conflict" else 400
1788
1789
  _pm_audit(resolved, "task", "update", res["id"])
1789
1790
  return jsonify({"updated": True, "task": res})
1790
1791
 
@@ -1796,7 +1797,7 @@ def api_pm_task():
1796
1797
  task_id = (data.get("id") or "").strip()
1797
1798
  if not task_id:
1798
1799
  return jsonify({"error": "id is required"}), 400
1799
- res = store.archive_task(task_id)
1800
+ res = store.archive_task(task_id, actor="hub")
1800
1801
  if "error" in res:
1801
1802
  return jsonify(res), 400
1802
1803
  _pm_audit(resolved, "task", "archive", res["id"])
@@ -1825,9 +1826,10 @@ def api_pm_milestone():
1825
1826
  return jsonify({"error": "id is required"}), 400
1826
1827
 
1827
1828
  if request.method == "PUT":
1828
- res = store.update_milestone(ms_id, **(data.get("fields") or {}))
1829
+ res = store.update_milestone(ms_id, expected_rev=data.get("expected_rev"),
1830
+ **(data.get("fields") or {}))
1829
1831
  if "error" in res:
1830
- return jsonify(res), 400
1832
+ return jsonify(res), 409 if res.get("code") == "rev_conflict" else 400
1831
1833
  _pm_audit(resolved, "milestone", "update", res["id"])
1832
1834
  return jsonify({"updated": True, "milestone": res})
1833
1835
 
@@ -1860,9 +1862,10 @@ def api_pm_note():
1860
1862
  return jsonify({"error": "id is required"}), 400
1861
1863
 
1862
1864
  if request.method == "PUT":
1863
- res = store.update_note(note_id, **(data.get("fields") or {}))
1865
+ res = store.update_note(note_id, expected_rev=data.get("expected_rev"),
1866
+ **(data.get("fields") or {}))
1864
1867
  if "error" in res:
1865
- return jsonify(res), 400
1868
+ return jsonify(res), 409 if res.get("code") == "rev_conflict" else 400
1866
1869
  _pm_audit(resolved, "note", "update", res["id"])
1867
1870
  return jsonify({"updated": True, "note": res})
1868
1871
 
@@ -1898,6 +1901,105 @@ def api_pm_link():
1898
1901
  return jsonify({"task": res})
1899
1902
 
1900
1903
 
1904
+ @app.route("/api/projects/pm/events", methods=["GET"])
1905
+ def api_pm_events():
1906
+ """PM event history for one project, newest first.
1907
+ Query: path, entity?, id?, op?, limit?"""
1908
+ resolved, err = _pm_resolve((request.args.get("path") or "").strip())
1909
+ if err:
1910
+ return err
1911
+ try:
1912
+ limit = max(1, min(int(request.args.get("limit") or 50), 500))
1913
+ except ValueError:
1914
+ limit = 50
1915
+ return jsonify({"path": str(resolved), "events": _pm_store(resolved).history(
1916
+ entity=(request.args.get("entity") or None),
1917
+ item_id=(request.args.get("id") or None),
1918
+ op=(request.args.get("op") or None),
1919
+ limit=limit)})
1920
+
1921
+
1922
+ @app.route("/api/projects/pm/deps", methods=["POST"])
1923
+ def api_pm_deps():
1924
+ """Add/remove a blocked-by dependency: {path, id, blocker, op: add|remove}."""
1925
+ data = request.get_json(force=True) or {}
1926
+ resolved, err = _pm_resolve((data.get("path") or "").strip())
1927
+ if err:
1928
+ return err
1929
+ task_id = (data.get("id") or "").strip()
1930
+ blocker = (data.get("blocker") or "").strip()
1931
+ op = (data.get("op") or "add").strip()
1932
+ if not task_id or not blocker:
1933
+ return jsonify({"error": "id and blocker are required"}), 400
1934
+ if op not in ("add", "remove"):
1935
+ return jsonify({"error": "op must be add|remove"}), 400
1936
+ store = _pm_store(resolved)
1937
+ res = (store.add_dependency(task_id, blocker, actor="hub") if op == "add"
1938
+ else store.remove_dependency(task_id, blocker, actor="hub"))
1939
+ if "error" in res:
1940
+ return jsonify(res), 400
1941
+ _pm_audit(resolved, "deps", op, res["id"])
1942
+ return jsonify({"task": res})
1943
+
1944
+
1945
+ @app.route("/api/projects/pm/report", methods=["GET"])
1946
+ def api_pm_report():
1947
+ """PM health report for one project. Query: path"""
1948
+ resolved, err = _pm_resolve((request.args.get("path") or "").strip())
1949
+ if err:
1950
+ return err
1951
+ return jsonify({"path": str(resolved),
1952
+ "report": _pm_store(resolved).report()})
1953
+
1954
+
1955
+ def _time_tracker(path):
1956
+ from services.time_tracker import TimeTracker
1957
+ return TimeTracker(str(path))
1958
+
1959
+
1960
+ @app.route("/api/projects/time", methods=["GET"])
1961
+ def api_projects_time():
1962
+ """Time summary for one project. Query: path"""
1963
+ resolved, err = _pm_resolve((request.args.get("path") or "").strip())
1964
+ if err:
1965
+ return err
1966
+ tracker = _time_tracker(resolved)
1967
+ return jsonify({"path": str(resolved), "summary": tracker.summary(),
1968
+ "sessions": tracker.sessions()[:20],
1969
+ "entries": tracker.list_entries(limit=100)})
1970
+
1971
+
1972
+ @app.route("/api/projects/time/entry", methods=["POST", "PUT", "DELETE"])
1973
+ def api_projects_time_entry():
1974
+ data = request.get_json(force=True) or {}
1975
+ resolved, err = _pm_resolve((data.get("path") or "").strip())
1976
+ if err:
1977
+ return err
1978
+ tracker = _time_tracker(resolved)
1979
+ if request.method == "POST":
1980
+ res = tracker.add_entry(data.get("minutes"), note=data.get("note", ""),
1981
+ date=data.get("date") or None,
1982
+ task_id=data.get("task_id"), created_by="hub")
1983
+ if "error" in res:
1984
+ return jsonify(res), 400
1985
+ _pm_audit(resolved, "time", "create", res["id"])
1986
+ return jsonify({"created": True, "entry": res}), 201
1987
+ entry_id = (data.get("id") or "").strip()
1988
+ if not entry_id:
1989
+ return jsonify({"error": "id is required"}), 400
1990
+ if request.method == "PUT":
1991
+ res = tracker.update_entry(entry_id, **(data.get("fields") or {}))
1992
+ if "error" in res:
1993
+ return jsonify(res), 400
1994
+ _pm_audit(resolved, "time", "update", res["id"])
1995
+ return jsonify({"updated": True, "entry": res})
1996
+ res = tracker.delete_entry(entry_id)
1997
+ if "error" in res:
1998
+ return jsonify(res), 400
1999
+ _pm_audit(resolved, "time", "delete", entry_id)
2000
+ return jsonify(res)
2001
+
2002
+
1901
2003
  # ── Agent artifacts: config tracking (v2.46.0) ────────────────────────────
1902
2004
  # Direct ArtifactStore per request (load-per-op store — no runtime build
1903
2005
  # needed); every mutation audited to the target project's activity log.
@@ -2012,24 +2114,47 @@ def api_pm_global():
2012
2114
  skipped.append({"path": ppath, "reason": "not initialized"})
2013
2115
  continue
2014
2116
  try:
2015
- if status_filter and status_filter != "all":
2016
- rows = TaskStore(ppath).list_tasks(status=status_filter, limit=1000)
2017
- else:
2018
- rows = TaskStore(ppath).list_tasks(limit=1000)
2019
- if status_filter != "all":
2020
- rows = [t for t in rows if t.get("status") != "done"]
2117
+ everything = TaskStore(ppath).list_tasks(include_archived=True,
2118
+ limit=1000)
2021
2119
  except Exception as e:
2022
2120
  skipped.append({"path": ppath, "reason": str(e)})
2023
2121
  continue
2122
+ active = [t for t in everything
2123
+ if t.get("lifecycle", "active") == "active"]
2124
+ if status_filter and status_filter != "all":
2125
+ rows = [t for t in active if t.get("status") == status_filter]
2126
+ elif status_filter == "all":
2127
+ rows = active
2128
+ else:
2129
+ rows = [t for t in active if t.get("status") != "done"]
2024
2130
  if not rows:
2025
2131
  continue
2132
+ # Resolve blockers server-side: the aggregate ships only open tasks,
2133
+ # so clients cannot tell a done/archived blocker from an open one.
2134
+ by_id = {t["id"]: t for t in everything}
2135
+ for t in rows:
2136
+ deps = t.get("blocked_by") or []
2137
+ if not deps:
2138
+ continue
2139
+ found = [(d, by_id.get(d)) for d in deps]
2140
+ t["blockers_open"] = sum(
2141
+ 1 for _, b in found
2142
+ if b is not None and b.get("lifecycle", "active") == "active"
2143
+ and b.get("status") != "done")
2144
+ t["blocker_titles"] = [
2145
+ (b.get("title") or d[:8]) if b is not None else d[:8]
2146
+ for d, b in found]
2026
2147
  proj_info = {"name": p.get("name"), "path": ppath}
2027
2148
  if p.get("parent_path"):
2028
2149
  proj_info["parent_path"] = p["parent_path"]
2029
2150
  for t in rows:
2030
2151
  t["project"] = proj_info
2031
2152
  tasks.extend(rows)
2032
- by_project[ppath] = {"name": p.get("name"), "open": len(rows)}
2153
+ by_project[ppath] = {
2154
+ "name": p.get("name"),
2155
+ "open": sum(1 for t in rows if t.get("status") != "done"),
2156
+ "shown": len(rows),
2157
+ }
2033
2158
 
2034
2159
  # priority asc, due asc, updated desc (stable two-stage sort)
2035
2160
  tasks.sort(key=lambda t: t.get("updated_at") or "", reverse=True)
@@ -6,7 +6,9 @@
6
6
  // Shared PM primitives (PM_COLUMNS, PriorityDot, DueBadge, statusColor,
7
7
  // ...) come from ui/pm_shared.js, loaded earlier in the bundle.
8
8
 
9
- function TaskBoardCard({ task, mode, colTasks, index, onMoveStatus, onMoveRank, onOpenProject }) {
9
+ let _pmDragTask = null; // active drag payload (module-level; no useRef in this bundle)
10
+
11
+ function TaskBoardCard({ task, mode, colTasks, index, onMoveStatus, onMoveRank, onOpenProject, onMoveTo, onDropOnCard, byId }) {
10
12
  const keys = PM_COLUMNS.map(c => c[0]);
11
13
  const ci = keys.indexOf(task.status);
12
14
  const navBtn = (label, title, onClick) => (
@@ -18,10 +20,15 @@ function TaskBoardCard({ task, mode, colTasks, index, onMoveStatus, onMoveRank,
18
20
  }}>{label}</button>
19
21
  );
20
22
  return (
21
- <div className="fade-up" style={{
22
- background: T.surface, border: `1px solid ${T.border}`, borderRadius: 8,
23
- padding: '8px 10px', display: 'flex', flexDirection: 'column', gap: 6,
24
- }}>
23
+ <div className="fade-up" draggable
24
+ onDragStart={() => { _pmDragTask = task; }}
25
+ onDragOver={e => e.preventDefault()}
26
+ onDrop={e => { e.preventDefault(); e.stopPropagation(); onDropOnCard(task); }}
27
+ style={{
28
+ background: T.surface, border: `1px solid ${T.border}`, borderRadius: 8,
29
+ padding: '8px 10px', display: 'flex', flexDirection: 'column', gap: 6,
30
+ cursor: 'grab',
31
+ }}>
25
32
  <div style={{ display: 'flex', alignItems: 'flex-start', gap: 6 }}>
26
33
  <span style={{ marginTop: 3, display: 'inline-flex', flexShrink: 0 }}>
27
34
  <PriorityDot priority={task.priority} />
@@ -37,10 +44,13 @@ function TaskBoardCard({ task, mode, colTasks, index, onMoveStatus, onMoveRank,
37
44
  <Badge color={T.purple}>{task.project.name || 'project'}</Badge>
38
45
  </span>
39
46
  )}
47
+ <DepsBadge task={task} byId={byId} />
40
48
  <DueBadge task={task} />
41
49
  {(task.tags || []).map(tag => <Badge key={tag} color={T.blue}>{tag}</Badge>)}
42
50
  </div>
43
51
  <div style={{ display: 'flex', alignItems: 'center', gap: 4 }}>
52
+ {isTaskReady(task, byId) &&
53
+ navBtn('✓', 'Unblocked — move to Backlog', () => onMoveTo(task, 'backlog'))}
44
54
  {ci > 0 && navBtn('◀', `Move to ${PM_COLUMNS[ci - 1][1]}`, () => onMoveStatus(task, -1))}
45
55
  {ci >= 0 && ci < keys.length - 1 &&
46
56
  navBtn('▶', `Move to ${PM_COLUMNS[ci + 1][1]}`, () => onMoveStatus(task, +1))}
@@ -61,6 +71,7 @@ function TaskBoard({ projects, onOpenDrill }) {
61
71
  const [msFilter, setMsFilter] = useState(''); // milestone id ('' = all)
62
72
  const [err, setErr] = useState('');
63
73
  const [newTitle, setNewTitle] = useState('');
74
+ const [timeData, setTimeData] = useState(null);
64
75
 
65
76
  const mode = scope === 'global' ? 'global' : 'project';
66
77
 
@@ -72,6 +83,10 @@ function TaskBoard({ projects, onOpenDrill }) {
72
83
  const q = msFilter ? `&milestone=${encodeURIComponent(msFilter)}` : '';
73
84
  const b = await api.get(`/api/projects/pm?path=${encodeURIComponent(scope)}${q}`);
74
85
  setBoardData(b);
86
+ try {
87
+ setTimeData(await api.get(
88
+ `/api/projects/time?path=${encodeURIComponent(scope)}`));
89
+ } catch (e2) { setTimeData(null); }
75
90
  }
76
91
  setErr('');
77
92
  } catch (e) {
@@ -85,7 +100,7 @@ function TaskBoard({ projects, onOpenDrill }) {
85
100
  }, [scope, msFilter]);
86
101
 
87
102
  // Reset per-project state when the scope changes (avoid stale board flash).
88
- useEffect(() => { setBoardData(null); setMsFilter(''); setNewTitle(''); setErr(''); }, [scope]);
103
+ useEffect(() => { setBoardData(null); setMsFilter(''); setNewTitle(''); setErr(''); setTimeData(null); }, [scope]);
89
104
  useEffect(() => { load(); }, [load]);
90
105
  usePoll(load, 10000);
91
106
 
@@ -98,10 +113,19 @@ function TaskBoard({ projects, onOpenDrill }) {
98
113
  const path = mode === 'global' ? (task.project && task.project.path) : scope;
99
114
  if (!path) return;
100
115
  try {
101
- await api.put('/api/projects/pm/task', { path, id: task.id, move: { status: next } });
116
+ const body = { path, id: task.id, move: { status: next } };
117
+ if (mode === 'project' && boardData && boardData.board && boardData.board.rev != null) {
118
+ body.expected_rev = boardData.board.rev;
119
+ }
120
+ await api.put('/api/projects/pm/task', body);
102
121
  notify(`Moved to ${PM_COLUMNS[ci + dir][1]}`);
103
122
  load();
104
- } catch (e) { notify(e.message || 'Move failed', 'err'); }
123
+ } catch (e) {
124
+ if (e && e.status === 409) {
125
+ notify('Board changed elsewhere — refreshed', 'err');
126
+ load();
127
+ } else { notify(e.message || 'Move failed', 'err'); }
128
+ }
105
129
  };
106
130
 
107
131
  const moveRank = async (task, colTasks, index, dir) => {
@@ -109,10 +133,47 @@ function TaskBoard({ projects, onOpenDrill }) {
109
133
  ? { before_id: colTasks[index - 1].id }
110
134
  : { after_id: colTasks[index + 1].id };
111
135
  try {
112
- await api.put('/api/projects/pm/task', { path: scope, id: task.id, move });
136
+ const body = { path: scope, id: task.id, move };
137
+ if (boardData && boardData.board && boardData.board.rev != null) {
138
+ body.expected_rev = boardData.board.rev;
139
+ }
140
+ await api.put('/api/projects/pm/task', body);
113
141
  notify(dir < 0 ? 'Moved up' : 'Moved down');
114
142
  load();
115
- } catch (e) { notify(e.message || 'Reorder failed', 'err'); }
143
+ } catch (e) {
144
+ if (e && e.status === 409) {
145
+ notify('Board changed elsewhere — refreshed', 'err');
146
+ load();
147
+ } else { notify(e.message || 'Reorder failed', 'err'); }
148
+ }
149
+ };
150
+
151
+ const moveTo = async (task, status) => {
152
+ const path = mode === 'global' ? (task.project && task.project.path) : scope;
153
+ if (!path || task.status === status) return;
154
+ try {
155
+ await api.put('/api/projects/pm/task', { path, id: task.id, move: { status } });
156
+ notify(`Moved to ${(PM_COLUMNS.find(c => c[0] === status) || [status, status])[1]}`);
157
+ load();
158
+ } catch (e) { notify(e.message || 'Move failed', 'err'); }
159
+ };
160
+
161
+ const dropOnColumn = (key) => {
162
+ const t = _pmDragTask; _pmDragTask = null;
163
+ if (!t) return;
164
+ moveTo(t, key);
165
+ };
166
+
167
+ const dropOnCard = (target) => {
168
+ const t = _pmDragTask; _pmDragTask = null;
169
+ if (!t || t.id === target.id) return;
170
+ if (mode !== 'project') { moveTo(t, target.status); return; }
171
+ const move = t.status === target.status
172
+ ? { before_id: target.id }
173
+ : { status: target.status, before_id: target.id };
174
+ api.put('/api/projects/pm/task', { path: scope, id: t.id, move })
175
+ .then(() => { notify('Moved'); load(); })
176
+ .catch(e => notify(e.message || 'Move failed', 'err'));
116
177
  };
117
178
 
118
179
  const addTask = async () => {
@@ -145,7 +206,11 @@ function TaskBoard({ projects, onOpenDrill }) {
145
206
  const cols = (((boardData || {}).board) || {}).columns || {};
146
207
  PM_COLUMNS.forEach(([k]) => { columns[k] = cols[k] || []; });
147
208
  }
209
+ const boardById = {};
210
+ Object.values(columns).forEach(list =>
211
+ list.forEach(t => { boardById[t.id] = t; }));
148
212
  const milestones = (((boardData || {}).board) || {}).milestones || [];
213
+ const recovery = (((boardData || {}).board) || {}).recovery || null;
149
214
  const byProject = (globalData || {}).by_project || {};
150
215
  const projChips = Object.entries(byProject)
151
216
  .sort((a, b) => (b[1].open || 0) - (a[1].open || 0) ||
@@ -191,7 +256,16 @@ function TaskBoard({ projects, onOpenDrill }) {
191
256
  </div>
192
257
  )}
193
258
 
259
+ {mode === 'project' && timeData && timeData.summary && (
260
+ <div className="mono" style={{ fontSize: 11, color: T.textDim }}>
261
+ ⏱ {fmtMinutes(timeData.summary.today.total_min)} today
262
+ {' · '}{fmtMinutes(timeData.summary.last_7d.total_min)} last 7d
263
+ {' · '}{fmtMinutes(timeData.summary.last_30d.total_min)} last 30d
264
+ {' · '}{(timeData.entries || []).length} manual
265
+ </div>
266
+ )}
194
267
  {err && <div style={{ fontSize: 12, color: T.error }}>{err}</div>}
268
+ {mode === 'project' && <RecoveryBanner recovery={recovery} />}
195
269
 
196
270
  {/* Board */}
197
271
  {loadingBoard ? (
@@ -214,10 +288,13 @@ function TaskBoard({ projects, onOpenDrill }) {
214
288
  {hiddenDone ? '—' : colTasks.length}
215
289
  </span>
216
290
  </div>
217
- <div style={{
218
- display: 'flex', flexDirection: 'column', gap: 8,
219
- overflowY: 'auto', maxHeight: 'calc(100vh - 220px)', paddingRight: 2,
220
- }}>
291
+ <div
292
+ onDragOver={e => e.preventDefault()}
293
+ onDrop={e => { e.preventDefault(); dropOnColumn(key); }}
294
+ style={{
295
+ display: 'flex', flexDirection: 'column', gap: 8,
296
+ overflowY: 'auto', maxHeight: 'calc(100vh - 220px)', paddingRight: 2,
297
+ }}>
221
298
  {mode === 'project' && key === 'backlog' && (
222
299
  <div style={{ display: 'flex', gap: 6 }}>
223
300
  <input value={newTitle}
@@ -246,9 +323,10 @@ function TaskBoard({ projects, onOpenDrill }) {
246
323
  <React.Fragment>
247
324
  {colTasks.map((t, i) => (
248
325
  <TaskBoardCard key={t.id} task={t} mode={mode}
249
- colTasks={colTasks} index={i}
326
+ colTasks={colTasks} index={i} byId={boardById}
250
327
  onMoveStatus={moveStatus} onMoveRank={moveRank}
251
- onOpenProject={openProject} />
328
+ onOpenProject={openProject}
329
+ onMoveTo={moveTo} onDropOnCard={dropOnCard} />
252
330
  ))}
253
331
  {colTasks.length === 0 && !(mode === 'project' && key === 'backlog') && (
254
332
  <div style={{ fontSize: 11, color: T.textDim, fontStyle: 'italic', padding: '4px 2px' }}>