code-context-control 2.89.1__tar.gz → 2.92.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 (449) hide show
  1. {code_context_control-2.89.1/code_context_control.egg-info → code_context_control-2.92.0}/PKG-INFO +2 -2
  2. {code_context_control-2.89.1 → code_context_control-2.92.0}/README.md +1 -1
  3. {code_context_control-2.89.1 → code_context_control-2.92.0}/cli/c3.py +286 -49
  4. {code_context_control-2.89.1 → code_context_control-2.92.0}/cli/commands/parser.py +9 -2
  5. {code_context_control-2.89.1 → code_context_control-2.92.0}/cli/guide/credentials.html +22 -5
  6. {code_context_control-2.89.1 → code_context_control-2.92.0}/cli/guide/oracle.html +18 -3
  7. {code_context_control-2.89.1 → code_context_control-2.92.0}/cli/hook_pretool_enforce.py +148 -0
  8. {code_context_control-2.89.1 → code_context_control-2.92.0}/cli/hub_server.py +100 -1
  9. {code_context_control-2.89.1 → code_context_control-2.92.0}/cli/hub_ui/app.js +2 -1
  10. {code_context_control-2.89.1 → code_context_control-2.92.0}/cli/hub_ui/components/hub_credentials.js +26 -3
  11. {code_context_control-2.89.1 → code_context_control-2.92.0}/cli/hub_ui/components/settings_modal.js +148 -33
  12. {code_context_control-2.89.1 → code_context_control-2.92.0}/cli/hub_ui/components/topbar.js +4 -1
  13. {code_context_control-2.89.1 → code_context_control-2.92.0}/cli/mcp_server.py +9 -5
  14. {code_context_control-2.89.1 → code_context_control-2.92.0}/cli/tools/credentials.py +9 -1
  15. {code_context_control-2.89.1 → code_context_control-2.92.0}/cli/ui/components/credentials.js +26 -3
  16. {code_context_control-2.89.1 → code_context_control-2.92.0/code_context_control.egg-info}/PKG-INFO +2 -2
  17. {code_context_control-2.89.1 → code_context_control-2.92.0}/code_context_control.egg-info/SOURCES.txt +10 -0
  18. {code_context_control-2.89.1 → code_context_control-2.92.0}/oracle/oracle_server.py +32 -11
  19. {code_context_control-2.89.1 → code_context_control-2.92.0}/oracle/oracle_ui.html +31 -0
  20. {code_context_control-2.89.1 → code_context_control-2.92.0}/oracle/services/local_session.py +72 -8
  21. {code_context_control-2.89.1 → code_context_control-2.92.0}/oracle/ui/chat/send.js +6 -1
  22. {code_context_control-2.89.1 → code_context_control-2.92.0}/oracle/ui/core.js +39 -0
  23. {code_context_control-2.89.1 → code_context_control-2.92.0}/oracle/ui/header.js +13 -1
  24. {code_context_control-2.89.1 → code_context_control-2.92.0}/pyproject.toml +1 -1
  25. code_context_control-2.92.0/services/background_service.py +662 -0
  26. {code_context_control-2.89.1 → code_context_control-2.92.0}/services/claude_md.py +39 -1
  27. {code_context_control-2.89.1 → code_context_control-2.92.0}/services/credential_store.py +83 -3
  28. {code_context_control-2.89.1 → code_context_control-2.92.0}/services/enforcement_policy.py +9 -3
  29. code_context_control-2.92.0/services/hub_service.py +78 -0
  30. code_context_control-2.92.0/services/oracle_service.py +141 -0
  31. code_context_control-2.92.0/services/repo_shape.py +129 -0
  32. code_context_control-2.92.0/tests/test_background_service.py +445 -0
  33. code_context_control-2.92.0/tests/test_credential_login_kind.py +191 -0
  34. code_context_control-2.92.0/tests/test_credential_ui_parity.py +146 -0
  35. {code_context_control-2.89.1 → code_context_control-2.92.0}/tests/test_hook_pretool_enforce.py +123 -0
  36. code_context_control-2.92.0/tests/test_hub_oracle_service_routes.py +202 -0
  37. code_context_control-2.92.0/tests/test_init_clear_preserves_user_content.py +236 -0
  38. code_context_control-2.92.0/tests/test_oracle_health_probe.py +73 -0
  39. {code_context_control-2.89.1 → code_context_control-2.92.0}/tests/test_oracle_session_bootstrap.py +69 -0
  40. code_context_control-2.92.0/tests/test_repo_shape.py +204 -0
  41. code_context_control-2.89.1/services/hub_service.py +0 -585
  42. {code_context_control-2.89.1 → code_context_control-2.92.0}/LICENSE +0 -0
  43. {code_context_control-2.89.1 → code_context_control-2.92.0}/cli/__init__.py +0 -0
  44. {code_context_control-2.89.1 → code_context_control-2.92.0}/cli/_hook_utils.py +0 -0
  45. {code_context_control-2.89.1 → code_context_control-2.92.0}/cli/commands/__init__.py +0 -0
  46. {code_context_control-2.89.1 → code_context_control-2.92.0}/cli/commands/common.py +0 -0
  47. {code_context_control-2.89.1 → code_context_control-2.92.0}/cli/docs.html +0 -0
  48. {code_context_control-2.89.1 → code_context_control-2.92.0}/cli/edits.html +0 -0
  49. {code_context_control-2.89.1 → code_context_control-2.92.0}/cli/guide/access.html +0 -0
  50. {code_context_control-2.89.1 → code_context_control-2.92.0}/cli/guide/bitbucket.html +0 -0
  51. {code_context_control-2.89.1 → code_context_control-2.92.0}/cli/guide/getting-started.html +0 -0
  52. {code_context_control-2.89.1 → code_context_control-2.92.0}/cli/guide/index.html +0 -0
  53. {code_context_control-2.89.1 → code_context_control-2.92.0}/cli/guide/masking.html +0 -0
  54. {code_context_control-2.89.1 → code_context_control-2.92.0}/cli/guide/shared.css +0 -0
  55. {code_context_control-2.89.1 → code_context_control-2.92.0}/cli/guide/tools.html +0 -0
  56. {code_context_control-2.89.1 → code_context_control-2.92.0}/cli/guide/workflow.html +0 -0
  57. {code_context_control-2.89.1 → code_context_control-2.92.0}/cli/hook_access_guard.py +0 -0
  58. {code_context_control-2.89.1 → code_context_control-2.92.0}/cli/hook_artifact.py +0 -0
  59. {code_context_control-2.89.1 → code_context_control-2.92.0}/cli/hook_auto_snapshot.py +0 -0
  60. {code_context_control-2.89.1 → code_context_control-2.92.0}/cli/hook_c3_signal.py +0 -0
  61. {code_context_control-2.89.1 → code_context_control-2.92.0}/cli/hook_c3read.py +0 -0
  62. {code_context_control-2.89.1 → code_context_control-2.92.0}/cli/hook_dispatch.py +0 -0
  63. {code_context_control-2.89.1 → code_context_control-2.92.0}/cli/hook_edit_ledger.py +0 -0
  64. {code_context_control-2.89.1 → code_context_control-2.92.0}/cli/hook_edit_unlock.py +0 -0
  65. {code_context_control-2.89.1 → code_context_control-2.92.0}/cli/hook_filter.py +0 -0
  66. {code_context_control-2.89.1 → code_context_control-2.92.0}/cli/hook_ghost_files.py +0 -0
  67. {code_context_control-2.89.1 → code_context_control-2.92.0}/cli/hook_prompt_recall.py +0 -0
  68. {code_context_control-2.89.1 → code_context_control-2.92.0}/cli/hook_read.py +0 -0
  69. {code_context_control-2.89.1 → code_context_control-2.92.0}/cli/hook_session_stats.py +0 -0
  70. {code_context_control-2.89.1 → code_context_control-2.92.0}/cli/hook_terse_advisor.py +0 -0
  71. {code_context_control-2.89.1 → code_context_control-2.92.0}/cli/hub_ui/components/add_project.js +0 -0
  72. {code_context_control-2.89.1 → code_context_control-2.92.0}/cli/hub_ui/components/config_editor.js +0 -0
  73. {code_context_control-2.89.1 → code_context_control-2.92.0}/cli/hub_ui/components/drill_artifacts.js +0 -0
  74. {code_context_control-2.89.1 → code_context_control-2.92.0}/cli/hub_ui/components/drill_health.js +0 -0
  75. {code_context_control-2.89.1 → code_context_control-2.92.0}/cli/hub_ui/components/drill_panel.js +0 -0
  76. {code_context_control-2.89.1 → code_context_control-2.92.0}/cli/hub_ui/components/drill_subprojects.js +0 -0
  77. {code_context_control-2.89.1 → code_context_control-2.92.0}/cli/hub_ui/components/drill_tasks.js +0 -0
  78. {code_context_control-2.89.1 → code_context_control-2.92.0}/cli/hub_ui/components/drill_views.js +0 -0
  79. {code_context_control-2.89.1 → code_context_control-2.92.0}/cli/hub_ui/components/global_search.js +0 -0
  80. {code_context_control-2.89.1 → code_context_control-2.92.0}/cli/hub_ui/components/hub_ci.js +0 -0
  81. {code_context_control-2.89.1 → code_context_control-2.92.0}/cli/hub_ui/components/hub_enforcement.js +0 -0
  82. {code_context_control-2.89.1 → code_context_control-2.92.0}/cli/hub_ui/components/hub_locks.js +0 -0
  83. {code_context_control-2.89.1 → code_context_control-2.92.0}/cli/hub_ui/components/mcp_manager.js +0 -0
  84. {code_context_control-2.89.1 → code_context_control-2.92.0}/cli/hub_ui/components/modals.js +0 -0
  85. {code_context_control-2.89.1 → code_context_control-2.92.0}/cli/hub_ui/components/project_card.js +0 -0
  86. {code_context_control-2.89.1 → code_context_control-2.92.0}/cli/hub_ui/components/project_tree.js +0 -0
  87. {code_context_control-2.89.1 → code_context_control-2.92.0}/cli/hub_ui/components/session_drawer.js +0 -0
  88. {code_context_control-2.89.1 → code_context_control-2.92.0}/cli/hub_ui/components/sidebar.js +0 -0
  89. {code_context_control-2.89.1 → code_context_control-2.92.0}/cli/hub_ui/components/summary_bar.js +0 -0
  90. {code_context_control-2.89.1 → code_context_control-2.92.0}/cli/hub_ui/components/task_board.js +0 -0
  91. {code_context_control-2.89.1 → code_context_control-2.92.0}/cli/hub_ui/components/toasts.js +0 -0
  92. {code_context_control-2.89.1 → code_context_control-2.92.0}/cli/hub_ui/state.js +0 -0
  93. {code_context_control-2.89.1 → code_context_control-2.92.0}/cli/hub_ui.html +0 -0
  94. {code_context_control-2.89.1 → code_context_control-2.92.0}/cli/mcp_proxy.py +0 -0
  95. {code_context_control-2.89.1 → code_context_control-2.92.0}/cli/progress.py +0 -0
  96. {code_context_control-2.89.1 → code_context_control-2.92.0}/cli/server.py +0 -0
  97. {code_context_control-2.89.1 → code_context_control-2.92.0}/cli/tools/__init__.py +0 -0
  98. {code_context_control-2.89.1 → code_context_control-2.92.0}/cli/tools/_grants.py +0 -0
  99. {code_context_control-2.89.1 → code_context_control-2.92.0}/cli/tools/_helpers.py +0 -0
  100. {code_context_control-2.89.1 → code_context_control-2.92.0}/cli/tools/agent.py +0 -0
  101. {code_context_control-2.89.1 → code_context_control-2.92.0}/cli/tools/artifacts.py +0 -0
  102. {code_context_control-2.89.1 → code_context_control-2.92.0}/cli/tools/bitbucket.py +0 -0
  103. {code_context_control-2.89.1 → code_context_control-2.92.0}/cli/tools/ci.py +0 -0
  104. {code_context_control-2.89.1 → code_context_control-2.92.0}/cli/tools/compress.py +0 -0
  105. {code_context_control-2.89.1 → code_context_control-2.92.0}/cli/tools/delegate.py +0 -0
  106. {code_context_control-2.89.1 → code_context_control-2.92.0}/cli/tools/edit.py +0 -0
  107. {code_context_control-2.89.1 → code_context_control-2.92.0}/cli/tools/edit_verify.py +0 -0
  108. {code_context_control-2.89.1 → code_context_control-2.92.0}/cli/tools/edits.py +0 -0
  109. {code_context_control-2.89.1 → code_context_control-2.92.0}/cli/tools/federate.py +0 -0
  110. {code_context_control-2.89.1 → code_context_control-2.92.0}/cli/tools/filter.py +0 -0
  111. {code_context_control-2.89.1 → code_context_control-2.92.0}/cli/tools/impact.py +0 -0
  112. {code_context_control-2.89.1 → code_context_control-2.92.0}/cli/tools/jira.py +0 -0
  113. {code_context_control-2.89.1 → code_context_control-2.92.0}/cli/tools/locks.py +0 -0
  114. {code_context_control-2.89.1 → code_context_control-2.92.0}/cli/tools/memory.py +0 -0
  115. {code_context_control-2.89.1 → code_context_control-2.92.0}/cli/tools/override.py +0 -0
  116. {code_context_control-2.89.1 → code_context_control-2.92.0}/cli/tools/project.py +0 -0
  117. {code_context_control-2.89.1 → code_context_control-2.92.0}/cli/tools/read.py +0 -0
  118. {code_context_control-2.89.1 → code_context_control-2.92.0}/cli/tools/search.py +0 -0
  119. {code_context_control-2.89.1 → code_context_control-2.92.0}/cli/tools/session.py +0 -0
  120. {code_context_control-2.89.1 → code_context_control-2.92.0}/cli/tools/shell.py +0 -0
  121. {code_context_control-2.89.1 → code_context_control-2.92.0}/cli/tools/status.py +0 -0
  122. {code_context_control-2.89.1 → code_context_control-2.92.0}/cli/tools/tasks.py +0 -0
  123. {code_context_control-2.89.1 → code_context_control-2.92.0}/cli/tools/validate.py +0 -0
  124. {code_context_control-2.89.1 → code_context_control-2.92.0}/cli/ui/api.js +0 -0
  125. {code_context_control-2.89.1 → code_context_control-2.92.0}/cli/ui/app.js +0 -0
  126. {code_context_control-2.89.1 → code_context_control-2.92.0}/cli/ui/components/access.js +0 -0
  127. {code_context_control-2.89.1 → code_context_control-2.92.0}/cli/ui/components/bitbucket.js +0 -0
  128. {code_context_control-2.89.1 → code_context_control-2.92.0}/cli/ui/components/chat.js +0 -0
  129. {code_context_control-2.89.1 → code_context_control-2.92.0}/cli/ui/components/dashboard.js +0 -0
  130. {code_context_control-2.89.1 → code_context_control-2.92.0}/cli/ui/components/edits.js +0 -0
  131. {code_context_control-2.89.1 → code_context_control-2.92.0}/cli/ui/components/enforcement.js +0 -0
  132. {code_context_control-2.89.1 → code_context_control-2.92.0}/cli/ui/components/instructions.js +0 -0
  133. {code_context_control-2.89.1 → code_context_control-2.92.0}/cli/ui/components/jira.js +0 -0
  134. {code_context_control-2.89.1 → code_context_control-2.92.0}/cli/ui/components/memory.js +0 -0
  135. {code_context_control-2.89.1 → code_context_control-2.92.0}/cli/ui/components/sessions.js +0 -0
  136. {code_context_control-2.89.1 → code_context_control-2.92.0}/cli/ui/components/settings.js +0 -0
  137. {code_context_control-2.89.1 → code_context_control-2.92.0}/cli/ui/components/sidebar.js +0 -0
  138. {code_context_control-2.89.1 → code_context_control-2.92.0}/cli/ui/components/tasks.js +0 -0
  139. {code_context_control-2.89.1 → code_context_control-2.92.0}/cli/ui/icons.js +0 -0
  140. {code_context_control-2.89.1 → code_context_control-2.92.0}/cli/ui/pm_shared.js +0 -0
  141. {code_context_control-2.89.1 → code_context_control-2.92.0}/cli/ui/shared.js +0 -0
  142. {code_context_control-2.89.1 → code_context_control-2.92.0}/cli/ui/theme.js +0 -0
  143. {code_context_control-2.89.1 → code_context_control-2.92.0}/cli/ui.html +0 -0
  144. {code_context_control-2.89.1 → code_context_control-2.92.0}/cli/ui_legacy.html +0 -0
  145. {code_context_control-2.89.1 → code_context_control-2.92.0}/cli/ui_nano.html +0 -0
  146. {code_context_control-2.89.1 → code_context_control-2.92.0}/code_context_control.egg-info/dependency_links.txt +0 -0
  147. {code_context_control-2.89.1 → code_context_control-2.92.0}/code_context_control.egg-info/entry_points.txt +0 -0
  148. {code_context_control-2.89.1 → code_context_control-2.92.0}/code_context_control.egg-info/requires.txt +0 -0
  149. {code_context_control-2.89.1 → code_context_control-2.92.0}/code_context_control.egg-info/top_level.txt +0 -0
  150. {code_context_control-2.89.1 → code_context_control-2.92.0}/core/__init__.py +0 -0
  151. {code_context_control-2.89.1 → code_context_control-2.92.0}/core/config.py +0 -0
  152. {code_context_control-2.89.1 → code_context_control-2.92.0}/core/ide.py +0 -0
  153. {code_context_control-2.89.1 → code_context_control-2.92.0}/core/mcp_toml.py +0 -0
  154. {code_context_control-2.89.1 → code_context_control-2.92.0}/core/web_security.py +0 -0
  155. {code_context_control-2.89.1 → code_context_control-2.92.0}/oracle/__init__.py +0 -0
  156. {code_context_control-2.89.1 → code_context_control-2.92.0}/oracle/config.py +0 -0
  157. {code_context_control-2.89.1 → code_context_control-2.92.0}/oracle/mcp_oracle.py +0 -0
  158. {code_context_control-2.89.1 → code_context_control-2.92.0}/oracle/services/__init__.py +0 -0
  159. {code_context_control-2.89.1 → code_context_control-2.92.0}/oracle/services/activity_reporter.py +0 -0
  160. {code_context_control-2.89.1 → code_context_control-2.92.0}/oracle/services/api_auth.py +0 -0
  161. {code_context_control-2.89.1 → code_context_control-2.92.0}/oracle/services/c3_bridge.py +0 -0
  162. {code_context_control-2.89.1 → code_context_control-2.92.0}/oracle/services/chat_engine.py +0 -0
  163. {code_context_control-2.89.1 → code_context_control-2.92.0}/oracle/services/chat_poll.py +0 -0
  164. {code_context_control-2.89.1 → code_context_control-2.92.0}/oracle/services/chat_store.py +0 -0
  165. {code_context_control-2.89.1 → code_context_control-2.92.0}/oracle/services/cross_memory.py +0 -0
  166. {code_context_control-2.89.1 → code_context_control-2.92.0}/oracle/services/discovery_audit.py +0 -0
  167. {code_context_control-2.89.1 → code_context_control-2.92.0}/oracle/services/federated_graph.py +0 -0
  168. {code_context_control-2.89.1 → code_context_control-2.92.0}/oracle/services/health_checker.py +0 -0
  169. {code_context_control-2.89.1 → code_context_control-2.92.0}/oracle/services/insight_engine.py +0 -0
  170. {code_context_control-2.89.1 → code_context_control-2.92.0}/oracle/services/memory_reader.py +0 -0
  171. {code_context_control-2.89.1 → code_context_control-2.92.0}/oracle/services/memory_writer.py +0 -0
  172. {code_context_control-2.89.1 → code_context_control-2.92.0}/oracle/services/mobile_api.py +0 -0
  173. {code_context_control-2.89.1 → code_context_control-2.92.0}/oracle/services/project_scanner.py +0 -0
  174. {code_context_control-2.89.1 → code_context_control-2.92.0}/oracle/services/review_agent.py +0 -0
  175. {code_context_control-2.89.1 → code_context_control-2.92.0}/oracle/services/tool_executor.py +0 -0
  176. {code_context_control-2.89.1 → code_context_control-2.92.0}/oracle/services/tool_registry.py +0 -0
  177. {code_context_control-2.89.1 → code_context_control-2.92.0}/oracle/ui/activity.js +0 -0
  178. {code_context_control-2.89.1 → code_context_control-2.92.0}/oracle/ui/agents.js +0 -0
  179. {code_context_control-2.89.1 → code_context_control-2.92.0}/oracle/ui/app.js +0 -0
  180. {code_context_control-2.89.1 → code_context_control-2.92.0}/oracle/ui/busy.js +0 -0
  181. {code_context_control-2.89.1 → code_context_control-2.92.0}/oracle/ui/chat/conversations.js +0 -0
  182. {code_context_control-2.89.1 → code_context_control-2.92.0}/oracle/ui/chat/input.js +0 -0
  183. {code_context_control-2.89.1 → code_context_control-2.92.0}/oracle/ui/chat/markdown.js +0 -0
  184. {code_context_control-2.89.1 → code_context_control-2.92.0}/oracle/ui/chat/stream_renderer.js +0 -0
  185. {code_context_control-2.89.1 → code_context_control-2.92.0}/oracle/ui/chat/toolbar.js +0 -0
  186. {code_context_control-2.89.1 → code_context_control-2.92.0}/oracle/ui/crossgraph.js +0 -0
  187. {code_context_control-2.89.1 → code_context_control-2.92.0}/oracle/ui/insights.js +0 -0
  188. {code_context_control-2.89.1 → code_context_control-2.92.0}/oracle/ui/projects.js +0 -0
  189. {code_context_control-2.89.1 → code_context_control-2.92.0}/oracle/ui/qrcode.js +0 -0
  190. {code_context_control-2.89.1 → code_context_control-2.92.0}/oracle/ui/settings.js +0 -0
  191. {code_context_control-2.89.1 → code_context_control-2.92.0}/oracle/ui/suggestions.js +0 -0
  192. {code_context_control-2.89.1 → code_context_control-2.92.0}/oracle/ui/theme_tabs.js +0 -0
  193. {code_context_control-2.89.1 → code_context_control-2.92.0}/services/__init__.py +0 -0
  194. {code_context_control-2.89.1 → code_context_control-2.92.0}/services/access_guard.py +0 -0
  195. {code_context_control-2.89.1 → code_context_control-2.92.0}/services/access_telemetry.py +0 -0
  196. {code_context_control-2.89.1 → code_context_control-2.92.0}/services/activity_log.py +0 -0
  197. {code_context_control-2.89.1 → code_context_control-2.92.0}/services/agent_base.py +0 -0
  198. {code_context_control-2.89.1 → code_context_control-2.92.0}/services/agent_locks.py +0 -0
  199. {code_context_control-2.89.1 → code_context_control-2.92.0}/services/agents.py +0 -0
  200. {code_context_control-2.89.1 → code_context_control-2.92.0}/services/artifact_defs.py +0 -0
  201. {code_context_control-2.89.1 → code_context_control-2.92.0}/services/artifact_store.py +0 -0
  202. {code_context_control-2.89.1 → code_context_control-2.92.0}/services/auto_memory.py +0 -0
  203. {code_context_control-2.89.1 → code_context_control-2.92.0}/services/bench/__init__.py +0 -0
  204. {code_context_control-2.89.1 → code_context_control-2.92.0}/services/bench/external/__init__.py +0 -0
  205. {code_context_control-2.89.1 → code_context_control-2.92.0}/services/bench/external/aider_polyglot.py +0 -0
  206. {code_context_control-2.89.1 → code_context_control-2.92.0}/services/bench/external/swe_bench.py +0 -0
  207. {code_context_control-2.89.1 → code_context_control-2.92.0}/services/benchmark_dashboard.py +0 -0
  208. {code_context_control-2.89.1 → code_context_control-2.92.0}/services/bitbucket_client.py +0 -0
  209. {code_context_control-2.89.1 → code_context_control-2.92.0}/services/bitbucket_credentials.py +0 -0
  210. {code_context_control-2.89.1 → code_context_control-2.92.0}/services/ci_act.py +0 -0
  211. {code_context_control-2.89.1 → code_context_control-2.92.0}/services/ci_cache.py +0 -0
  212. {code_context_control-2.89.1 → code_context_control-2.92.0}/services/ci_expr.py +0 -0
  213. {code_context_control-2.89.1 → code_context_control-2.92.0}/services/ci_failures.py +0 -0
  214. {code_context_control-2.89.1 → code_context_control-2.92.0}/services/ci_github.py +0 -0
  215. {code_context_control-2.89.1 → code_context_control-2.92.0}/services/ci_impact.py +0 -0
  216. {code_context_control-2.89.1 → code_context_control-2.92.0}/services/ci_intel.py +0 -0
  217. {code_context_control-2.89.1 → code_context_control-2.92.0}/services/ci_runner.py +0 -0
  218. {code_context_control-2.89.1 → code_context_control-2.92.0}/services/ci_workflow.py +0 -0
  219. {code_context_control-2.89.1 → code_context_control-2.92.0}/services/circuit_breaker.py +0 -0
  220. {code_context_control-2.89.1 → code_context_control-2.92.0}/services/compressor.py +0 -0
  221. {code_context_control-2.89.1 → code_context_control-2.92.0}/services/context_snapshot.py +0 -0
  222. {code_context_control-2.89.1 → code_context_control-2.92.0}/services/conversation_store.py +0 -0
  223. {code_context_control-2.89.1 → code_context_control-2.92.0}/services/cred_telemetry.py +0 -0
  224. {code_context_control-2.89.1 → code_context_control-2.92.0}/services/doc_index.py +0 -0
  225. {code_context_control-2.89.1 → code_context_control-2.92.0}/services/e2e_benchmark.py +0 -0
  226. {code_context_control-2.89.1 → code_context_control-2.92.0}/services/e2e_evaluator.py +0 -0
  227. {code_context_control-2.89.1 → code_context_control-2.92.0}/services/e2e_tasks.py +0 -0
  228. {code_context_control-2.89.1 → code_context_control-2.92.0}/services/edit_ledger.py +0 -0
  229. {code_context_control-2.89.1 → code_context_control-2.92.0}/services/embedding_index.py +0 -0
  230. {code_context_control-2.89.1 → code_context_control-2.92.0}/services/error_reporting.py +0 -0
  231. {code_context_control-2.89.1 → code_context_control-2.92.0}/services/file_memory.py +0 -0
  232. {code_context_control-2.89.1 → code_context_control-2.92.0}/services/git_context.py +0 -0
  233. {code_context_control-2.89.1 → code_context_control-2.92.0}/services/indexer.py +0 -0
  234. {code_context_control-2.89.1 → code_context_control-2.92.0}/services/jira_client.py +0 -0
  235. {code_context_control-2.89.1 → code_context_control-2.92.0}/services/jira_cloud.py +0 -0
  236. {code_context_control-2.89.1 → code_context_control-2.92.0}/services/jira_credentials.py +0 -0
  237. {code_context_control-2.89.1 → code_context_control-2.92.0}/services/jira_data_center.py +0 -0
  238. {code_context_control-2.89.1 → code_context_control-2.92.0}/services/jira_links.py +0 -0
  239. {code_context_control-2.89.1 → code_context_control-2.92.0}/services/mask_activation.py +0 -0
  240. {code_context_control-2.89.1 → code_context_control-2.92.0}/services/mask_mirror.py +0 -0
  241. {code_context_control-2.89.1 → code_context_control-2.92.0}/services/mask_presets.py +0 -0
  242. {code_context_control-2.89.1 → code_context_control-2.92.0}/services/memory.py +0 -0
  243. {code_context_control-2.89.1 → code_context_control-2.92.0}/services/memory_consolidator.py +0 -0
  244. {code_context_control-2.89.1 → code_context_control-2.92.0}/services/memory_distiller.py +0 -0
  245. {code_context_control-2.89.1 → code_context_control-2.92.0}/services/memory_graph.py +0 -0
  246. {code_context_control-2.89.1 → code_context_control-2.92.0}/services/memory_grounder.py +0 -0
  247. {code_context_control-2.89.1 → code_context_control-2.92.0}/services/memory_queue.py +0 -0
  248. {code_context_control-2.89.1 → code_context_control-2.92.0}/services/memory_scorer.py +0 -0
  249. {code_context_control-2.89.1 → code_context_control-2.92.0}/services/metrics.py +0 -0
  250. {code_context_control-2.89.1 → code_context_control-2.92.0}/services/notifications.py +0 -0
  251. {code_context_control-2.89.1 → code_context_control-2.92.0}/services/ollama_bridge.py +0 -0
  252. {code_context_control-2.89.1 → code_context_control-2.92.0}/services/ollama_client.py +0 -0
  253. {code_context_control-2.89.1 → code_context_control-2.92.0}/services/ollama_credentials.py +0 -0
  254. {code_context_control-2.89.1 → code_context_control-2.92.0}/services/output_filter.py +0 -0
  255. {code_context_control-2.89.1 → code_context_control-2.92.0}/services/override_grants.py +0 -0
  256. {code_context_control-2.89.1 → code_context_control-2.92.0}/services/override_policy.py +0 -0
  257. {code_context_control-2.89.1 → code_context_control-2.92.0}/services/override_requests.py +0 -0
  258. {code_context_control-2.89.1 → code_context_control-2.92.0}/services/override_wake.py +0 -0
  259. {code_context_control-2.89.1 → code_context_control-2.92.0}/services/parser.py +0 -0
  260. {code_context_control-2.89.1 → code_context_control-2.92.0}/services/project_manager.py +0 -0
  261. {code_context_control-2.89.1 → code_context_control-2.92.0}/services/project_runtime.py +0 -0
  262. {code_context_control-2.89.1 → code_context_control-2.92.0}/services/protocol.py +0 -0
  263. {code_context_control-2.89.1 → code_context_control-2.92.0}/services/proxy_state.py +0 -0
  264. {code_context_control-2.89.1 → code_context_control-2.92.0}/services/repo_map.py +0 -0
  265. {code_context_control-2.89.1 → code_context_control-2.92.0}/services/retention.py +0 -0
  266. {code_context_control-2.89.1 → code_context_control-2.92.0}/services/retrieval_broker.py +0 -0
  267. {code_context_control-2.89.1 → code_context_control-2.92.0}/services/router.py +0 -0
  268. {code_context_control-2.89.1 → code_context_control-2.92.0}/services/runtime.py +0 -0
  269. {code_context_control-2.89.1 → code_context_control-2.92.0}/services/scanner.py +0 -0
  270. {code_context_control-2.89.1 → code_context_control-2.92.0}/services/session_benchmark.py +0 -0
  271. {code_context_control-2.89.1 → code_context_control-2.92.0}/services/session_manager.py +0 -0
  272. {code_context_control-2.89.1 → code_context_control-2.92.0}/services/session_preloader.py +0 -0
  273. {code_context_control-2.89.1 → code_context_control-2.92.0}/services/subprojects.py +0 -0
  274. {code_context_control-2.89.1 → code_context_control-2.92.0}/services/task_store.py +0 -0
  275. {code_context_control-2.89.1 → code_context_control-2.92.0}/services/telemetry.py +0 -0
  276. {code_context_control-2.89.1 → code_context_control-2.92.0}/services/text_index.py +0 -0
  277. {code_context_control-2.89.1 → code_context_control-2.92.0}/services/time_tracker.py +0 -0
  278. {code_context_control-2.89.1 → code_context_control-2.92.0}/services/tool_classifier.py +0 -0
  279. {code_context_control-2.89.1 → code_context_control-2.92.0}/services/transcript_index.py +0 -0
  280. {code_context_control-2.89.1 → code_context_control-2.92.0}/services/validation_cache.py +0 -0
  281. {code_context_control-2.89.1 → code_context_control-2.92.0}/services/vector_store.py +0 -0
  282. {code_context_control-2.89.1 → code_context_control-2.92.0}/services/watcher.py +0 -0
  283. {code_context_control-2.89.1 → code_context_control-2.92.0}/services/win_subprocess.py +0 -0
  284. {code_context_control-2.89.1 → code_context_control-2.92.0}/setup.cfg +0 -0
  285. {code_context_control-2.89.1 → code_context_control-2.92.0}/tests/test_access_builtin_optout.py +0 -0
  286. {code_context_control-2.89.1 → code_context_control-2.92.0}/tests/test_access_guard.py +0 -0
  287. {code_context_control-2.89.1 → code_context_control-2.92.0}/tests/test_access_guard_meta.py +0 -0
  288. {code_context_control-2.89.1 → code_context_control-2.92.0}/tests/test_access_guard_shell_project.py +0 -0
  289. {code_context_control-2.89.1 → code_context_control-2.92.0}/tests/test_access_guard_surfaces.py +0 -0
  290. {code_context_control-2.89.1 → code_context_control-2.92.0}/tests/test_access_guard_wiring.py +0 -0
  291. {code_context_control-2.89.1 → code_context_control-2.92.0}/tests/test_activity_reporter.py +0 -0
  292. {code_context_control-2.89.1 → code_context_control-2.92.0}/tests/test_agent_locks.py +0 -0
  293. {code_context_control-2.89.1 → code_context_control-2.92.0}/tests/test_aider_polyglot.py +0 -0
  294. {code_context_control-2.89.1 → code_context_control-2.92.0}/tests/test_antigravity_transition.py +0 -0
  295. {code_context_control-2.89.1 → code_context_control-2.92.0}/tests/test_artifact_store.py +0 -0
  296. {code_context_control-2.89.1 → code_context_control-2.92.0}/tests/test_artifact_tool.py +0 -0
  297. {code_context_control-2.89.1 → code_context_control-2.92.0}/tests/test_bitbucket_cli_smoke.py +0 -0
  298. {code_context_control-2.89.1 → code_context_control-2.92.0}/tests/test_bitbucket_client.py +0 -0
  299. {code_context_control-2.89.1 → code_context_control-2.92.0}/tests/test_bitbucket_config_fallback.py +0 -0
  300. {code_context_control-2.89.1 → code_context_control-2.92.0}/tests/test_bitbucket_credentials.py +0 -0
  301. {code_context_control-2.89.1 → code_context_control-2.92.0}/tests/test_bitbucket_tool.py +0 -0
  302. {code_context_control-2.89.1 → code_context_control-2.92.0}/tests/test_c3_bridge_project_artifacts.py +0 -0
  303. {code_context_control-2.89.1 → code_context_control-2.92.0}/tests/test_c3_shell.py +0 -0
  304. {code_context_control-2.89.1 → code_context_control-2.92.0}/tests/test_chat_poll.py +0 -0
  305. {code_context_control-2.89.1 → code_context_control-2.92.0}/tests/test_ci_act.py +0 -0
  306. {code_context_control-2.89.1 → code_context_control-2.92.0}/tests/test_ci_cache.py +0 -0
  307. {code_context_control-2.89.1 → code_context_control-2.92.0}/tests/test_ci_expr.py +0 -0
  308. {code_context_control-2.89.1 → code_context_control-2.92.0}/tests/test_ci_impact.py +0 -0
  309. {code_context_control-2.89.1 → code_context_control-2.92.0}/tests/test_ci_intel.py +0 -0
  310. {code_context_control-2.89.1 → code_context_control-2.92.0}/tests/test_ci_runner.py +0 -0
  311. {code_context_control-2.89.1 → code_context_control-2.92.0}/tests/test_ci_workflow.py +0 -0
  312. {code_context_control-2.89.1 → code_context_control-2.92.0}/tests/test_circuit_breaker.py +0 -0
  313. {code_context_control-2.89.1 → code_context_control-2.92.0}/tests/test_claude_md_merge.py +0 -0
  314. {code_context_control-2.89.1 → code_context_control-2.92.0}/tests/test_cli_smoke.py +0 -0
  315. {code_context_control-2.89.1 → code_context_control-2.92.0}/tests/test_compressor_large_file.py +0 -0
  316. {code_context_control-2.89.1 → code_context_control-2.92.0}/tests/test_cred_telemetry.py +0 -0
  317. {code_context_control-2.89.1 → code_context_control-2.92.0}/tests/test_credential_store.py +0 -0
  318. {code_context_control-2.89.1 → code_context_control-2.92.0}/tests/test_credentials_routes.py +0 -0
  319. {code_context_control-2.89.1 → code_context_control-2.92.0}/tests/test_credentials_tool.py +0 -0
  320. {code_context_control-2.89.1 → code_context_control-2.92.0}/tests/test_creds_cli_smoke.py +0 -0
  321. {code_context_control-2.89.1 → code_context_control-2.92.0}/tests/test_delegate_cascade.py +0 -0
  322. {code_context_control-2.89.1 → code_context_control-2.92.0}/tests/test_delegate_version_probe.py +0 -0
  323. {code_context_control-2.89.1 → code_context_control-2.92.0}/tests/test_e2e_benchmark.py +0 -0
  324. {code_context_control-2.89.1 → code_context_control-2.92.0}/tests/test_edit_ledger_deadline.py +0 -0
  325. {code_context_control-2.89.1 → code_context_control-2.92.0}/tests/test_edit_ledger_hook.py +0 -0
  326. {code_context_control-2.89.1 → code_context_control-2.92.0}/tests/test_edit_locking.py +0 -0
  327. {code_context_control-2.89.1 → code_context_control-2.92.0}/tests/test_edit_normalization.py +0 -0
  328. {code_context_control-2.89.1 → code_context_control-2.92.0}/tests/test_edit_verify.py +0 -0
  329. {code_context_control-2.89.1 → code_context_control-2.92.0}/tests/test_embedding_index_deadlock.py +0 -0
  330. {code_context_control-2.89.1 → code_context_control-2.92.0}/tests/test_enforcement_flip.py +0 -0
  331. {code_context_control-2.89.1 → code_context_control-2.92.0}/tests/test_enforcement_policy.py +0 -0
  332. {code_context_control-2.89.1 → code_context_control-2.92.0}/tests/test_enforcement_routes.py +0 -0
  333. {code_context_control-2.89.1 → code_context_control-2.92.0}/tests/test_federated_graph.py +0 -0
  334. {code_context_control-2.89.1 → code_context_control-2.92.0}/tests/test_filter_backoff.py +0 -0
  335. {code_context_control-2.89.1 → code_context_control-2.92.0}/tests/test_ghost_files.py +0 -0
  336. {code_context_control-2.89.1 → code_context_control-2.92.0}/tests/test_ghost_generation.py +0 -0
  337. {code_context_control-2.89.1 → code_context_control-2.92.0}/tests/test_git_branch_awareness.py +0 -0
  338. {code_context_control-2.89.1 → code_context_control-2.92.0}/tests/test_hook_access_guard.py +0 -0
  339. {code_context_control-2.89.1 → code_context_control-2.92.0}/tests/test_hook_codex_compat.py +0 -0
  340. {code_context_control-2.89.1 → code_context_control-2.92.0}/tests/test_hook_dispatch.py +0 -0
  341. {code_context_control-2.89.1 → code_context_control-2.92.0}/tests/test_hook_prompt_recall.py +0 -0
  342. {code_context_control-2.89.1 → code_context_control-2.92.0}/tests/test_hook_smoke.py +0 -0
  343. {code_context_control-2.89.1 → code_context_control-2.92.0}/tests/test_hook_state.py +0 -0
  344. {code_context_control-2.89.1 → code_context_control-2.92.0}/tests/test_hook_utf8_stdio.py +0 -0
  345. {code_context_control-2.89.1 → code_context_control-2.92.0}/tests/test_hub_credentials_route.py +0 -0
  346. {code_context_control-2.89.1 → code_context_control-2.92.0}/tests/test_hub_credentials_routes_write.py +0 -0
  347. {code_context_control-2.89.1 → code_context_control-2.92.0}/tests/test_hub_enforcement_routes.py +0 -0
  348. {code_context_control-2.89.1 → code_context_control-2.92.0}/tests/test_hub_inspect_api.py +0 -0
  349. {code_context_control-2.89.1 → code_context_control-2.92.0}/tests/test_hub_locks_routes.py +0 -0
  350. {code_context_control-2.89.1 → code_context_control-2.92.0}/tests/test_hub_server_smoke.py +0 -0
  351. {code_context_control-2.89.1 → code_context_control-2.92.0}/tests/test_hub_subproject_links.py +0 -0
  352. {code_context_control-2.89.1 → code_context_control-2.92.0}/tests/test_ide_workflow_adaptation.py +0 -0
  353. {code_context_control-2.89.1 → code_context_control-2.92.0}/tests/test_init_scan.py +0 -0
  354. {code_context_control-2.89.1 → code_context_control-2.92.0}/tests/test_install_mcp_entrypoint.py +0 -0
  355. {code_context_control-2.89.1 → code_context_control-2.92.0}/tests/test_jira_cli_smoke.py +0 -0
  356. {code_context_control-2.89.1 → code_context_control-2.92.0}/tests/test_jira_client.py +0 -0
  357. {code_context_control-2.89.1 → code_context_control-2.92.0}/tests/test_jira_config_fallback.py +0 -0
  358. {code_context_control-2.89.1 → code_context_control-2.92.0}/tests/test_jira_credentials.py +0 -0
  359. {code_context_control-2.89.1 → code_context_control-2.92.0}/tests/test_jira_links.py +0 -0
  360. {code_context_control-2.89.1 → code_context_control-2.92.0}/tests/test_jira_routes.py +0 -0
  361. {code_context_control-2.89.1 → code_context_control-2.92.0}/tests/test_jira_tool.py +0 -0
  362. {code_context_control-2.89.1 → code_context_control-2.92.0}/tests/test_lazy_store_init.py +0 -0
  363. {code_context_control-2.89.1 → code_context_control-2.92.0}/tests/test_mask_guard.py +0 -0
  364. {code_context_control-2.89.1 → code_context_control-2.92.0}/tests/test_mask_routes.py +0 -0
  365. {code_context_control-2.89.1 → code_context_control-2.92.0}/tests/test_mask_surfaces.py +0 -0
  366. {code_context_control-2.89.1 → code_context_control-2.92.0}/tests/test_mcp_host_guard.py +0 -0
  367. {code_context_control-2.89.1 → code_context_control-2.92.0}/tests/test_mcp_memory_timeout.py +0 -0
  368. {code_context_control-2.89.1 → code_context_control-2.92.0}/tests/test_mcp_server_smoke.py +0 -0
  369. {code_context_control-2.89.1 → code_context_control-2.92.0}/tests/test_mcp_toml.py +0 -0
  370. {code_context_control-2.89.1 → code_context_control-2.92.0}/tests/test_memory_distiller.py +0 -0
  371. {code_context_control-2.89.1 → code_context_control-2.92.0}/tests/test_memory_graph_api.py +0 -0
  372. {code_context_control-2.89.1 → code_context_control-2.92.0}/tests/test_memory_queue.py +0 -0
  373. {code_context_control-2.89.1 → code_context_control-2.92.0}/tests/test_memory_system.py +0 -0
  374. {code_context_control-2.89.1 → code_context_control-2.92.0}/tests/test_mobile_api.py +0 -0
  375. {code_context_control-2.89.1 → code_context_control-2.92.0}/tests/test_mobile_extras.py +0 -0
  376. {code_context_control-2.89.1 → code_context_control-2.92.0}/tests/test_mobile_override_routes.py +0 -0
  377. {code_context_control-2.89.1 → code_context_control-2.92.0}/tests/test_mobile_security_api.py +0 -0
  378. {code_context_control-2.89.1 → code_context_control-2.92.0}/tests/test_no_stale_model_pins.py +0 -0
  379. {code_context_control-2.89.1 → code_context_control-2.92.0}/tests/test_notification_dedup.py +0 -0
  380. {code_context_control-2.89.1 → code_context_control-2.92.0}/tests/test_notification_discipline.py +0 -0
  381. {code_context_control-2.89.1 → code_context_control-2.92.0}/tests/test_ollama_credentials.py +0 -0
  382. {code_context_control-2.89.1 → code_context_control-2.92.0}/tests/test_oracle_api_auth.py +0 -0
  383. {code_context_control-2.89.1 → code_context_control-2.92.0}/tests/test_oracle_apikey_api.py +0 -0
  384. {code_context_control-2.89.1 → code_context_control-2.92.0}/tests/test_oracle_c3_bridge.py +0 -0
  385. {code_context_control-2.89.1 → code_context_control-2.92.0}/tests/test_oracle_chat_engine.py +0 -0
  386. {code_context_control-2.89.1 → code_context_control-2.92.0}/tests/test_oracle_chat_store.py +0 -0
  387. {code_context_control-2.89.1 → code_context_control-2.92.0}/tests/test_oracle_discovery_api.py +0 -0
  388. {code_context_control-2.89.1 → code_context_control-2.92.0}/tests/test_oracle_discovery_audit.py +0 -0
  389. {code_context_control-2.89.1 → code_context_control-2.92.0}/tests/test_oracle_local_auth.py +0 -0
  390. {code_context_control-2.89.1 → code_context_control-2.92.0}/tests/test_oracle_ollama_bridge.py +0 -0
  391. {code_context_control-2.89.1 → code_context_control-2.92.0}/tests/test_oracle_scanner_cache.py +0 -0
  392. {code_context_control-2.89.1 → code_context_control-2.92.0}/tests/test_oracle_security_fixes.py +0 -0
  393. {code_context_control-2.89.1 → code_context_control-2.92.0}/tests/test_oracle_subproject_awareness.py +0 -0
  394. {code_context_control-2.89.1 → code_context_control-2.92.0}/tests/test_oracle_ui_bundle.py +0 -0
  395. {code_context_control-2.89.1 → code_context_control-2.92.0}/tests/test_output_filter.py +0 -0
  396. {code_context_control-2.89.1 → code_context_control-2.92.0}/tests/test_override_grants.py +0 -0
  397. {code_context_control-2.89.1 → code_context_control-2.92.0}/tests/test_override_grants_mcp.py +0 -0
  398. {code_context_control-2.89.1 → code_context_control-2.92.0}/tests/test_override_requests.py +0 -0
  399. {code_context_control-2.89.1 → code_context_control-2.92.0}/tests/test_override_wake.py +0 -0
  400. {code_context_control-2.89.1 → code_context_control-2.92.0}/tests/test_permissions.py +0 -0
  401. {code_context_control-2.89.1 → code_context_control-2.92.0}/tests/test_pm_api.py +0 -0
  402. {code_context_control-2.89.1 → code_context_control-2.92.0}/tests/test_project_manager.py +0 -0
  403. {code_context_control-2.89.1 → code_context_control-2.92.0}/tests/test_project_manager_merge.py +0 -0
  404. {code_context_control-2.89.1 → code_context_control-2.92.0}/tests/test_project_tool.py +0 -0
  405. {code_context_control-2.89.1 → code_context_control-2.92.0}/tests/test_read_coercion.py +0 -0
  406. {code_context_control-2.89.1 → code_context_control-2.92.0}/tests/test_read_edit_parity.py +0 -0
  407. {code_context_control-2.89.1 → code_context_control-2.92.0}/tests/test_related_facts.py +0 -0
  408. {code_context_control-2.89.1 → code_context_control-2.92.0}/tests/test_repo_map.py +0 -0
  409. {code_context_control-2.89.1 → code_context_control-2.92.0}/tests/test_response_boilerplate.py +0 -0
  410. {code_context_control-2.89.1 → code_context_control-2.92.0}/tests/test_retention.py +0 -0
  411. {code_context_control-2.89.1 → code_context_control-2.92.0}/tests/test_review_digest.py +0 -0
  412. {code_context_control-2.89.1 → code_context_control-2.92.0}/tests/test_service_durability.py +0 -0
  413. {code_context_control-2.89.1 → code_context_control-2.92.0}/tests/test_session_benchmark.py +0 -0
  414. {code_context_control-2.89.1 → code_context_control-2.92.0}/tests/test_session_budget.py +0 -0
  415. {code_context_control-2.89.1 → code_context_control-2.92.0}/tests/test_shell_creds.py +0 -0
  416. {code_context_control-2.89.1 → code_context_control-2.92.0}/tests/test_shell_robustness.py +0 -0
  417. {code_context_control-2.89.1 → code_context_control-2.92.0}/tests/test_subproject_exclusion.py +0 -0
  418. {code_context_control-2.89.1 → code_context_control-2.92.0}/tests/test_subproject_federation.py +0 -0
  419. {code_context_control-2.89.1 → code_context_control-2.92.0}/tests/test_subprojects.py +0 -0
  420. {code_context_control-2.89.1 → code_context_control-2.92.0}/tests/test_swe_bench.py +0 -0
  421. {code_context_control-2.89.1 → code_context_control-2.92.0}/tests/test_task_store.py +0 -0
  422. {code_context_control-2.89.1 → code_context_control-2.92.0}/tests/test_task_tool.py +0 -0
  423. {code_context_control-2.89.1 → code_context_control-2.92.0}/tests/test_time_tracker.py +0 -0
  424. {code_context_control-2.89.1 → code_context_control-2.92.0}/tests/test_token_telemetry.py +0 -0
  425. {code_context_control-2.89.1 → code_context_control-2.92.0}/tests/test_tool_registry.py +0 -0
  426. {code_context_control-2.89.1 → code_context_control-2.92.0}/tests/test_upgrade_and_version.py +0 -0
  427. {code_context_control-2.89.1 → code_context_control-2.92.0}/tests/test_validate.py +0 -0
  428. {code_context_control-2.89.1 → code_context_control-2.92.0}/tests/test_vault_write_guard.py +0 -0
  429. {code_context_control-2.89.1 → code_context_control-2.92.0}/tests/test_version_sync.py +0 -0
  430. {code_context_control-2.89.1 → code_context_control-2.92.0}/tests/test_web_security.py +0 -0
  431. {code_context_control-2.89.1 → code_context_control-2.92.0}/tests/test_windows_reliability.py +0 -0
  432. {code_context_control-2.89.1 → code_context_control-2.92.0}/tui/__init__.py +0 -0
  433. {code_context_control-2.89.1 → code_context_control-2.92.0}/tui/backend.py +0 -0
  434. {code_context_control-2.89.1 → code_context_control-2.92.0}/tui/main.py +0 -0
  435. {code_context_control-2.89.1 → code_context_control-2.92.0}/tui/screens/__init__.py +0 -0
  436. {code_context_control-2.89.1 → code_context_control-2.92.0}/tui/screens/benchmark_view.py +0 -0
  437. {code_context_control-2.89.1 → code_context_control-2.92.0}/tui/screens/claudemd_view.py +0 -0
  438. {code_context_control-2.89.1 → code_context_control-2.92.0}/tui/screens/compress_view.py +0 -0
  439. {code_context_control-2.89.1 → code_context_control-2.92.0}/tui/screens/index_view.py +0 -0
  440. {code_context_control-2.89.1 → code_context_control-2.92.0}/tui/screens/init_view.py +0 -0
  441. {code_context_control-2.89.1 → code_context_control-2.92.0}/tui/screens/mcp_view.py +0 -0
  442. {code_context_control-2.89.1 → code_context_control-2.92.0}/tui/screens/optimize_view.py +0 -0
  443. {code_context_control-2.89.1 → code_context_control-2.92.0}/tui/screens/pipe_view.py +0 -0
  444. {code_context_control-2.89.1 → code_context_control-2.92.0}/tui/screens/projects_view.py +0 -0
  445. {code_context_control-2.89.1 → code_context_control-2.92.0}/tui/screens/search_view.py +0 -0
  446. {code_context_control-2.89.1 → code_context_control-2.92.0}/tui/screens/session_view.py +0 -0
  447. {code_context_control-2.89.1 → code_context_control-2.92.0}/tui/screens/stats.py +0 -0
  448. {code_context_control-2.89.1 → code_context_control-2.92.0}/tui/screens/ui_view.py +0 -0
  449. {code_context_control-2.89.1 → code_context_control-2.92.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.89.1
3
+ Version: 2.92.0
4
4
  Summary: Local MCP code-intelligence for AI coding tools: surgical search/read/edit, agent-config version history, path-level access + masking guards, and a multi-project hub.
5
5
  Author-email: Dimitri Tselenchuk <dtselenc@gmail.com>
6
6
  License-Expression: Apache-2.0
@@ -137,7 +137,7 @@ Full notes: [Upgrading](https://github.com/drknowhow/code-context-control/blob/m
137
137
 
138
138
  ## The UI
139
139
 
140
- Three local web apps, no Electron — pure Flask + vanilla JS: the **Hub** (`c3 hub`, port 3330), the **per-project UI** (`c3 ui`), and the optional **Oracle** (`c3 oracle serve`).
140
+ Three local web apps, no Electron — pure Flask + vanilla JS: the **Hub** (`c3 hub`, port 3330), the **per-project UI** (`c3 ui`), and the optional **Oracle** (`c3 oracle serve`). Both servers can run as windowless login services — `c3 hub --install`, `c3 oracle serve --install`, or the buttons in Hub → Settings.
141
141
 
142
142
  ### Project Hub — multi-project mission control
143
143
 
@@ -74,7 +74,7 @@ Full notes: [Upgrading](https://github.com/drknowhow/code-context-control/blob/m
74
74
 
75
75
  ## The UI
76
76
 
77
- Three local web apps, no Electron — pure Flask + vanilla JS: the **Hub** (`c3 hub`, port 3330), the **per-project UI** (`c3 ui`), and the optional **Oracle** (`c3 oracle serve`).
77
+ Three local web apps, no Electron — pure Flask + vanilla JS: the **Hub** (`c3 hub`, port 3330), the **per-project UI** (`c3 ui`), and the optional **Oracle** (`c3 oracle serve`). Both servers can run as windowless login services — `c3 hub --install`, `c3 oracle serve --install`, or the buttons in Hub → Settings.
78
78
 
79
79
  ### Project Hub — multi-project mission control
80
80
 
@@ -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.89.1"
95
+ __version__ = "2.92.0"
96
96
 
97
97
 
98
98
  def _compress_file_cli(compressor, path, mode="smart", **kw):
@@ -845,7 +845,8 @@ def _prompt_memory_llm(project_path: str) -> None:
845
845
  + ("cloud + local fallback." if section["cloud_enabled"] else "local only (private)."))
846
846
 
847
847
 
848
- def _prompt_init_steps(project_path: str, ide_name: str, default_mode: str = "direct") -> tuple[str, bool]:
848
+ def _prompt_init_steps(project_path: str, ide_name: str, default_mode: str = "direct",
849
+ shape=None) -> tuple[str, bool]:
849
850
  """Run guided post-init setup steps for Git and MCP."""
850
851
  chosen_ide = _select_init_ide(ide_name or "auto")
851
852
  save_config({"ide": chosen_ide}, project_path)
@@ -916,7 +917,7 @@ def _prompt_init_steps(project_path: str, ide_name: str, default_mode: str = "di
916
917
  )
917
918
  include_wildcard = bool(wildcard_choice and wildcard_choice.startswith("Yes"))
918
919
 
919
- chosen_enforcement = _prompt_enforcement(chosen_tier)
920
+ chosen_enforcement = _prompt_enforcement(chosen_tier, shape=shape)
920
921
 
921
922
  _run_install_mcp(project_path, chosen_ide, mcp_mode=mcp_mode,
922
923
  permissions=chosen_tier, include_mcp_wildcard=include_wildcard,
@@ -924,9 +925,70 @@ def _prompt_init_steps(project_path: str, ide_name: str, default_mode: str = "di
924
925
  return chosen_ide, True
925
926
 
926
927
 
927
- def _prompt_enforcement(chosen_tier: str | None) -> str | None:
928
+ def _assess_repo_shape(project_path: str):
929
+ """Measure the project (services.repo_shape). None when it cannot be measured."""
930
+ try:
931
+ from services import repo_shape
932
+ return repo_shape.assess(project_path)
933
+ except Exception:
934
+ _log.debug("repo shape assessment failed", exc_info=True)
935
+ return None
936
+
937
+
938
+ def _apply_repo_shape_default(project_path: str, explicit_enforcement: str | None = None,
939
+ shape=None) -> None:
940
+ """Say what kind of project this is, and default a prose one to ``advisory``.
941
+
942
+ Field report 2026-08-22: a 636-file project, ~95% Markdown and .docx,
943
+ where every symbol-aware C3 tool had nothing to act on and strict
944
+ discipline was paid on every turn until C3 was uninstalled. The shape
945
+ is printed for every project; the default is written only for the prose
946
+ kind, only over a tier-derived or unset mode (never over ``c3 enforce``
947
+ or ``--enforcement``), with provenance ``set_by: repo-shape`` so
948
+ ``c3 enforce`` shows where it came from, and with the way back printed.
949
+ """
950
+ try:
951
+ from services import enforcement_policy as ep
952
+ from services import repo_shape
953
+ except Exception:
954
+ return
955
+ if shape is None:
956
+ shape = _assess_repo_shape(project_path)
957
+ if shape is None or shape.kind == repo_shape.KIND_EMPTY:
958
+ return
959
+ print(f"\n Repo shape: {shape.describe()}")
960
+ mode = repo_shape.recommended_mode(shape)
961
+ if not mode:
962
+ return
963
+ if explicit_enforcement:
964
+ print(f" Prose-heavy, but --enforcement {explicit_enforcement} was given — leaving it as set.")
965
+ return
966
+ current = ep.resolve(project_path)
967
+ if current.set_by == ep.SET_BY_USER:
968
+ print(f" Prose-heavy; tool discipline stays '{current.mode}' (your choice).")
969
+ return
970
+ if current.mode == mode:
971
+ print(f" Prose-heavy; tool discipline is already '{mode}'.")
972
+ return
973
+ try:
974
+ result = ep.set_mode(mode, project_path, set_by=ep.SET_BY_SHAPE, scope="project")
975
+ except ValueError:
976
+ return
977
+ if result.get("deferred"):
978
+ return
979
+ print(" [!] This is a documentation project: C3's symbol-aware tools (compress/read/impact/")
980
+ print(f" validate/CI) have little to act on here, so tool discipline is set to '{mode}' —")
981
+ print(" native Edit/Write are allowed with a nudge and the edit ledger still records them.")
982
+ print(" `c3 enforce strict` restores the hard block; `c3 enforce` shows the setting.")
983
+
984
+
985
+ def _prompt_enforcement(chosen_tier: str | None, shape=None) -> str | None:
928
986
  """Step 5/5 — tool discipline. Returns an explicit mode, or None to derive.
929
987
 
988
+ ``shape`` (services.repo_shape.RepoShape) moves the suggested default to
989
+ ``advisory`` for a documentation project and says why, so the user is
990
+ not asked to guess what C3's symbol tools will do with 600 Markdown files.
991
+
930
992
  Asked separately from the permission tier because it answers a genuinely
931
993
  different question: the tier controls what the IDE will let the agent call,
932
994
  this controls how hard C3's own hook pushes it toward c3_* tools. Users hit
@@ -938,8 +1000,18 @@ def _prompt_enforcement(chosen_tier: str | None) -> str | None:
938
1000
  return None
939
1001
 
940
1002
  default_mode = ep.derive_from_tier(chosen_tier) if chosen_tier else ep.MODE_ADVISORY
1003
+ suggested_by = "Your permission tier suggests"
1004
+ try:
1005
+ from services import repo_shape
1006
+ shape_mode = repo_shape.recommended_mode(shape) if shape is not None else None
1007
+ except Exception:
1008
+ shape_mode = None
1009
+ if shape_mode:
1010
+ default_mode = shape_mode
1011
+ suggested_by = ("This is a documentation project — C3's symbol tools have "
1012
+ "little to act on here. Suggested")
941
1013
  print()
942
- print(f" (Your permission tier suggests: {default_mode})")
1014
+ print(f" ({suggested_by}: {default_mode})")
943
1015
  choice = _prompt_choice(
944
1016
  "Step 5/5 — Tool discipline: how hard should C3 push toward c3_* tools?",
945
1017
  [
@@ -1085,6 +1157,7 @@ def cmd_init(args):
1085
1157
  if not c3_dir.exists() or not (c3_dir / "config.json").exists():
1086
1158
  print_header(f"Initializing C3 for: {project_path}")
1087
1159
  _do_init(project_path, ide_name=requested_ide, no_embed=no_embed)
1160
+ shape = _assess_repo_shape(project_path)
1088
1161
  try:
1089
1162
  from services.project_manager import ProjectManager
1090
1163
  ProjectManager().add_project(project_path)
@@ -1101,7 +1174,11 @@ def cmd_init(args):
1101
1174
  enforcement=getattr(args, "enforcement", None),
1102
1175
  )
1103
1176
  else:
1104
- _prompt_init_steps(project_path, requested_ide, default_mode=getattr(args, "mcp_mode", "direct"))
1177
+ _prompt_init_steps(project_path, requested_ide,
1178
+ default_mode=getattr(args, "mcp_mode", "direct"), shape=shape)
1179
+ _apply_repo_shape_default(project_path,
1180
+ explicit_enforcement=getattr(args, "enforcement", None),
1181
+ shape=shape)
1105
1182
  # Detect Codex CLI availability
1106
1183
  try:
1107
1184
  from cli.tools.delegate import check_codex
@@ -1285,11 +1362,7 @@ def cmd_init(args):
1285
1362
  if c3_dir.exists():
1286
1363
  shutil.rmtree(c3_dir)
1287
1364
  print(" Deleted .c3/")
1288
- for filename, _ in _instruction_documents_for_project():
1289
- p = Path(project_path) / filename
1290
- if p.exists():
1291
- p.unlink()
1292
- print(f" Deleted {filename}")
1365
+ _remove_c3_instruction_docs(project_path)
1293
1366
  print("\n[OK] C3 project files removed.")
1294
1367
  return
1295
1368
 
@@ -1361,9 +1434,10 @@ def cmd_init(args):
1361
1434
 
1362
1435
  elif selected.startswith("Wipe"):
1363
1436
  confirm = input(
1364
- "\n WARNING: This will permanently delete .c3/ and all project\n"
1365
- " instruction files (CLAUDE.md, GEMINI.md, AGENTS.md), and remove\n"
1366
- " C3 MCP configurations from your IDE. Type 'yes' to confirm: "
1437
+ "\n WARNING: This will permanently delete .c3/, remove C3's managed\n"
1438
+ " block from CLAUDE.md / AGENTS.md / GEMINI.md (a file is deleted only\n"
1439
+ " when nothing else is in it), and remove C3 MCP configurations from\n"
1440
+ " your IDE. Type 'yes' to confirm: "
1367
1441
  ).strip().lower()
1368
1442
  if confirm != "yes":
1369
1443
  print(" Wipe cancelled.")
@@ -1375,11 +1449,7 @@ def cmd_init(args):
1375
1449
  shutil.rmtree(c3_dir)
1376
1450
  print(" Deleted .c3/")
1377
1451
 
1378
- for filename, _ in _instruction_documents_for_project():
1379
- p = Path(project_path) / filename
1380
- if p.exists():
1381
- p.unlink()
1382
- print(f" Deleted {filename}")
1452
+ _remove_c3_instruction_docs(project_path)
1383
1453
 
1384
1454
  print("\n[OK] C3 project files removed.")
1385
1455
 
@@ -4555,6 +4625,115 @@ def _ensure_global_session_fallbacks(server_script: str, c3_mcp_exe: str | None
4555
4625
  print(f"Warning: Could not update {antigravity_path} (global fallback skipped)")
4556
4626
 
4557
4627
 
4628
+ # Every hook script C3 has ever registered in a settings file — the v2.42+
4629
+ # dispatcher plus the pre-v2.42 per-hook scripts — so uninstall recognises an
4630
+ # entry written by any C3 version. A user hook is anything not naming one.
4631
+ _C3_HOOK_SCRIPTS = (
4632
+ "hook_dispatch.py",
4633
+ "hook_access_guard.py", "hook_artifact.py", "hook_auto_snapshot.py",
4634
+ "hook_c3_signal.py", "hook_c3read.py", "hook_edit_ledger.py",
4635
+ "hook_edit_unlock.py", "hook_filter.py", "hook_ghost_files.py",
4636
+ "hook_pretool_enforce.py", "hook_prompt_recall.py", "hook_read.py",
4637
+ "hook_session_stats.py", "hook_terse_advisor.py",
4638
+ )
4639
+
4640
+
4641
+ def _is_c3_hook_command(command) -> bool:
4642
+ return any(script in str(command or "") for script in _C3_HOOK_SCRIPTS)
4643
+
4644
+
4645
+ def _is_c3_permission(rule) -> bool:
4646
+ """``mcp__c3__<tool>``, ``mcp__c3__*``, or the bare ``mcp__c3`` server grant."""
4647
+ r = str(rule or "").strip()
4648
+ return r == "mcp__c3" or r.startswith("mcp__c3__")
4649
+
4650
+
4651
+ def _c3_references_in_settings(settings: dict) -> list:
4652
+ """Every C3-owned entry present in a settings dict: hook commands (named
4653
+ by event) and permission rules. Used to decide whether there is anything
4654
+ to remove and, after writing, to check that it was actually removed."""
4655
+ refs: list = []
4656
+ hooks = settings.get("hooks")
4657
+ if isinstance(hooks, dict):
4658
+ for event, groups in hooks.items():
4659
+ for group in groups or []:
4660
+ if not isinstance(group, dict):
4661
+ continue
4662
+ for hk in group.get("hooks") or []:
4663
+ if isinstance(hk, dict) and _is_c3_hook_command(hk.get("command")):
4664
+ refs.append(f"hooks.{event}")
4665
+ perms = settings.get("permissions")
4666
+ if isinstance(perms, dict):
4667
+ for key in ("allow", "deny", "ask"):
4668
+ for rule in perms.get(key) or []:
4669
+ if _is_c3_permission(rule):
4670
+ refs.append(f"permissions.{key}:{rule}")
4671
+ if "c3" in (settings.get("enabledMcpjsonServers") or []):
4672
+ refs.append("enabledMcpjsonServers:c3")
4673
+ return refs
4674
+
4675
+
4676
+ def _strip_c3_from_settings(settings: dict) -> dict:
4677
+ """Remove every C3-owned entry from a Claude Code settings dict (in place,
4678
+ and returned). Touches ONLY what C3 wrote: hook entries whose command runs
4679
+ a C3 hook script — any event, any matcher; the previous cleanup looked at
4680
+ three PostToolUse matchers from the pre-v2.42 layout and nothing else, so
4681
+ PreToolUse/Stop/UserPromptSubmit and the whole ``permissions.allow`` list
4682
+ survived an "uninstall" — plus ``mcp__c3__*`` permission rules and the
4683
+ ``c3`` MCP-server enablement. User hooks, user permission rules and every
4684
+ other key are left exactly as found; containers emptied by the removal
4685
+ are dropped so a file C3 created alone ends up empty (and the caller
4686
+ deletes it) rather than as ``{"hooks": {}}``.
4687
+ """
4688
+ hooks = settings.get("hooks")
4689
+ if isinstance(hooks, dict):
4690
+ for event in list(hooks.keys()):
4691
+ kept_groups = []
4692
+ for group in hooks.get(event) or []:
4693
+ if not isinstance(group, dict):
4694
+ kept_groups.append(group)
4695
+ continue
4696
+ entries = group.get("hooks") or []
4697
+ if not any(isinstance(hk, dict) and _is_c3_hook_command(hk.get("command"))
4698
+ for hk in entries):
4699
+ kept_groups.append(group) # not ours — untouched
4700
+ continue
4701
+ kept = [hk for hk in entries
4702
+ if not (isinstance(hk, dict) and _is_c3_hook_command(hk.get("command")))]
4703
+ if kept:
4704
+ group = dict(group)
4705
+ group["hooks"] = kept
4706
+ kept_groups.append(group)
4707
+ if kept_groups:
4708
+ hooks[event] = kept_groups
4709
+ else:
4710
+ del hooks[event]
4711
+ if not hooks:
4712
+ del settings["hooks"]
4713
+
4714
+ perms = settings.get("permissions")
4715
+ if isinstance(perms, dict):
4716
+ for key in ("allow", "deny", "ask"):
4717
+ rules = perms.get(key)
4718
+ if isinstance(rules, list) and any(_is_c3_permission(r) for r in rules):
4719
+ kept_rules = [r for r in rules if not _is_c3_permission(r)]
4720
+ if kept_rules:
4721
+ perms[key] = kept_rules
4722
+ else:
4723
+ del perms[key]
4724
+ if not perms:
4725
+ del settings["permissions"]
4726
+
4727
+ enabled = settings.get("enabledMcpjsonServers")
4728
+ if isinstance(enabled, list) and "c3" in enabled:
4729
+ enabled = [s for s in enabled if s != "c3"]
4730
+ if enabled:
4731
+ settings["enabledMcpjsonServers"] = enabled
4732
+ else:
4733
+ del settings["enabledMcpjsonServers"]
4734
+ return settings
4735
+
4736
+
4558
4737
  def _uninstall_mcp_all(project_path: str, include_global: bool = True):
4559
4738
  """Remove C3 MCP server configurations from all supported IDEs.
4560
4739
 
@@ -4658,37 +4837,28 @@ def _uninstall_mcp_all(project_path: str, include_global: bool = True):
4658
4837
  with open(settings_path, 'r', encoding="utf-8") as f:
4659
4838
  settings = json.load(f)
4660
4839
 
4661
- # Remove hooks
4662
- hooks = settings.get("hooks", {}).get("PostToolUse", [])
4663
- new_hooks = []
4664
- c3_hook_files = {"hook_filter.py", "hook_read.py", "hook_c3read.py", "hook_dispatch.py"}
4665
- for h in hooks:
4666
- if h.get("matcher") in ("Bash", "Read", "mcp__c3__c3_read"):
4667
- h["hooks"] = [hook for hook in h.get("hooks", [])
4668
- if not any(f in hook.get("command", "") for f in c3_hook_files)]
4669
- if h["hooks"]:
4670
- new_hooks.append(h)
4671
- else:
4672
- new_hooks.append(h)
4673
-
4674
- if new_hooks:
4675
- settings["hooks"]["PostToolUse"] = new_hooks
4676
- elif "hooks" in settings and "PostToolUse" in settings["hooks"]:
4677
- del settings["hooks"]["PostToolUse"]
4678
- if not settings["hooks"]:
4679
- del settings["hooks"]
4680
-
4681
- # Remove enabled server
4682
- if "enabledMcpjsonServers" in settings and "c3" in settings["enabledMcpjsonServers"]:
4683
- settings["enabledMcpjsonServers"].remove("c3")
4684
-
4685
- if not settings:
4686
- settings_path.unlink()
4687
- print(f" Deleted empty {settings_path}")
4840
+ before = _c3_references_in_settings(settings)
4841
+ if not before:
4842
+ print(f" No C3 entries in {settings_path}")
4688
4843
  else:
4689
- with open(settings_path, 'w', encoding="utf-8") as f:
4690
- json.dump(settings, f, indent=2)
4691
- print(f" Removed C3 hooks/settings from {settings_path}")
4844
+ settings = _strip_c3_from_settings(settings)
4845
+ if not settings:
4846
+ settings_path.unlink()
4847
+ print(f" Deleted empty {settings_path}")
4848
+ else:
4849
+ with open(settings_path, 'w', encoding="utf-8") as f:
4850
+ json.dump(settings, f, indent=2)
4851
+ # Postcondition: re-read what is on disk and report
4852
+ # what is true, not what was attempted.
4853
+ with open(settings_path, 'r', encoding="utf-8") as f:
4854
+ remaining = _c3_references_in_settings(json.load(f))
4855
+ if remaining:
4856
+ shown = ", ".join(remaining[:5]) + (" ..." if len(remaining) > 5 else "")
4857
+ print(f" [!] C3 entries remain in {settings_path} "
4858
+ f"({len(remaining)}): {shown}")
4859
+ else:
4860
+ print(f" Removed C3 hooks/settings from {settings_path} "
4861
+ f"({len(before)} entries)")
4692
4862
  except Exception as e:
4693
4863
  print(f" Warning: Could not update {settings_path}: {e}")
4694
4864
 
@@ -4872,6 +5042,44 @@ def _instruction_documents_for_project() -> list[tuple[str, str]]:
4872
5042
  ]
4873
5043
 
4874
5044
 
5045
+ def _remove_c3_instruction_docs(project_path: str) -> None:
5046
+ """Take C3's managed block OUT of every instruction doc it ever wrote.
5047
+
5048
+ Uninstall counterpart of ``_sync_project_instruction_docs``. Before
5049
+ v2.92 this was a bare ``unlink()`` of CLAUDE.md / AGENTS.md / GEMINI.md —
5050
+ which, in a project whose CLAUDE.md also carried another tool's managed
5051
+ block (``<!-- YEP:BEGIN -->``) or the user's own notes, destroyed content
5052
+ C3 never owned, with no warning and no way back unless git had it.
5053
+ Same rule every regeneration path already follows: C3 owns its slice,
5054
+ everything outside the markers is preserved. A file is deleted only when
5055
+ the block was all there was.
5056
+ """
5057
+ from services.claude_md import strip_c3_block
5058
+
5059
+ for filename, _ in _instruction_documents_for_project():
5060
+ p = Path(project_path) / filename
5061
+ if not p.exists():
5062
+ continue
5063
+ try:
5064
+ existing = p.read_text(encoding="utf-8", errors="replace")
5065
+ except OSError as exc:
5066
+ print(f" Warning: Could not read {filename}: {exc}")
5067
+ continue
5068
+ remainder = strip_c3_block(existing)
5069
+ if remainder is None:
5070
+ print(f" Kept {filename} (no C3 block in it — not ours to delete)")
5071
+ elif remainder.strip():
5072
+ try:
5073
+ p.write_text(remainder, encoding="utf-8")
5074
+ except OSError as exc:
5075
+ print(f" Warning: Could not update {filename}: {exc}")
5076
+ continue
5077
+ print(f" Removed C3 block from {filename} (kept the rest of the file)")
5078
+ else:
5079
+ p.unlink()
5080
+ print(f" Deleted {filename}")
5081
+
5082
+
4875
5083
  _LEGACY_INSTRUCTION_DOCS = ("GEMINI.md",) # Gemini CLI profile removed in v2.52
4876
5084
 
4877
5085
 
@@ -7426,10 +7634,39 @@ def _oracle_open(args):
7426
7634
  webbrowser.open(url)
7427
7635
 
7428
7636
 
7637
+ def _oracle_service_cmd(args):
7638
+ """`c3 oracle serve --install | --uninstall | --status` — mirrors `c3 hub`."""
7639
+ from services.oracle_service import OracleService
7640
+ svc = OracleService()
7641
+ port = getattr(args, "port", None) or svc.default_port()
7642
+
7643
+ if getattr(args, "install", False):
7644
+ res = svc.install(port)
7645
+ print(res.get("output", "Service installed."))
7646
+ if res.get("success"):
7647
+ print(f"Oracle will start at login (no terminal window); log: {svc.LOG_FILE}")
7648
+ return
7649
+ if getattr(args, "uninstall", False):
7650
+ res = svc.uninstall()
7651
+ print(res.get("output", "Service uninstalled."))
7652
+ return
7653
+ res = svc.status()
7654
+ print(f"Oracle Service Status ({res.get('platform', 'unknown')}):")
7655
+ print(f" Installed: {res.get('installed')}")
7656
+ print(f" Running : {res.get('running')}")
7657
+ print(f" Port : {res.get('port')} (bind {res.get('bind_host')}, MCP {res.get('mcp_port')})")
7658
+ print(f" URL : {res.get('url')}")
7659
+ print(f" Method : {res.get('method')}")
7660
+ print(f" Log : {res.get('log_path')}")
7661
+
7662
+
7429
7663
  def cmd_oracle(args):
7430
7664
  """Oracle dashboard server + Discovery API key management."""
7431
7665
  sub = getattr(args, "oracle_cmd", None)
7432
7666
  if sub in ("serve", "start"):
7667
+ if any(getattr(args, f, False) for f in ("install", "uninstall", "status")):
7668
+ _oracle_service_cmd(args)
7669
+ return
7433
7670
  # Lazy import: run_oracle builds all Oracle services (matches
7434
7671
  # cmd_hub's deferred-import style so bare `c3` stays fast).
7435
7672
  from oracle.oracle_server import run_oracle
@@ -421,9 +421,9 @@ def build_parser(version: str, parse_cli_ide_arg):
421
421
  cr_set.add_argument("--stdin", action="store_true", help="Read the value from stdin (piped/multiline values)")
422
422
  cr_set.add_argument("--type", dest="ctype",
423
423
  choices=["token", "env", "multiline",
424
- "address", "identity", "card"],
424
+ "address", "identity", "card", "login"],
425
425
  default="token",
426
- help="Entry type; address/identity/card are structured "
426
+ help="Entry type; address/identity/card/login are structured "
427
427
  "(field payload, inject-only, never revealable to the agent)")
428
428
  cr_set.add_argument("--desc", default="", help="Human description shown in list/UI")
429
429
  cr_set.add_argument("--env-var", default="", help="Env var name used at injection (default: entry name)")
@@ -824,6 +824,13 @@ def build_parser(version: str, parse_cli_ide_arg):
824
824
  help="Server port (default: config 'port', 3331)")
825
825
  or_serve.add_argument("--no-browser", action="store_true",
826
826
  help="Don't open the browser")
827
+ or_serve.add_argument("--install", action="store_true",
828
+ help="Register the Oracle as a login/startup service "
829
+ "(no terminal window) and start it now")
830
+ or_serve.add_argument("--uninstall", action="store_true",
831
+ help="Remove the Oracle's startup service registration")
832
+ or_serve.add_argument("--status", action="store_true",
833
+ help="Show the Oracle's startup service status")
827
834
  or_open = or_subs.add_parser(
828
835
  "open",
829
836
  help="Sign in to a running dashboard via a single-use URL",
@@ -297,12 +297,14 @@ c3_shell(cmd=<span class="str">'terraform apply'</span>, env_creds=<span class="
297
297
 
298
298
  <!-- ═══════════════════════════════════ STRUCTURED ═══ -->
299
299
  <section id="structured" class="tool-section">
300
- <h2>Structured kinds — cards, addresses, identity (v2.87.0)</h2>
300
+ <h2>Structured kinds — cards, addresses, identity, logins (v2.87.0)</h2>
301
301
 
302
- <p>Three entry types hold <strong>named fields</strong> instead of one opaque value:
302
+ <p>Four entry types hold <strong>named fields</strong> instead of one opaque value:
303
303
  <code>card</code> (cardholder, number, expiry, optional cvc/billing_zip — Luhn-checked),
304
- <code>address</code> (street1, city, state, zip, optional recipient/street2/country/phone) and
305
- <code>identity</code> (full_name, optional dob/ssn/phone/email). The payload is stored as one
304
+ <code>address</code> (street1, city, state, zip, optional recipient/street2/country/phone),
305
+ <code>identity</code> (full_name, optional dob/ssn/phone/email) and
306
+ <code>login</code> (site_id, canonical_origin, username, password, optional totp_secret —
307
+ v2.90.0). The payload is stored as one
306
308
  canonical JSON object through the same keyring / encrypted-sidecar path as any other value.</p>
307
309
 
308
310
  <p>They are <strong>inject-only by construction</strong>, which is stricter than a normal secret:</p>
@@ -315,7 +317,10 @@ c3_shell(cmd=<span class="str">'terraform apply'</span>, env_creds=<span class="
315
317
  the field list rather than expanding the whole payload.</li>
316
318
  <li><strong>The registry shows a projection, not the data.</strong> Lists and the UI display
317
319
  <code>visa ••••4242</code> for a card (brand + last4, deliberately <em>not</em> expiry),
318
- city/state for an address, the name for an identity. Field <em>names</em> are public;
320
+ city/state for an address, the name for an identity, and
321
+ <code>github · https://github.com · 2FA</code> for a login — site, origin and a 2FA
322
+ boolean, with the <em>username withheld on purpose</em>, because username + origin is
323
+ half the credential. Field <em>names</em> are public;
319
324
  field <em>values</em> never transit any HTTP response — a sweep test enforces this.</li>
320
325
  <li><strong>Echoes redact per field</strong> to <code>[cred:NAME.field]</code>. Caveat: the
321
326
  redactor only tracks values of 4+ characters, so a 3-digit CVC or 2-letter state that a
@@ -333,6 +338,18 @@ c3_shell(cmd=<span class="str">'terraform apply'</span>, env_creds=<span class="
333
338
  <code>c3 creds get NAME --show</code> (all fields) or <code>--show --field number</code> —
334
339
  the browser and the mobile gateway never carry the values, and mobile cannot create
335
340
  structured entries at all.</p>
341
+
342
+ <p><strong><code>login</code> is storage only, and that is a design constraint, not a
343
+ gap.</strong> C3 has no browser surface and must not grow one: a login runner in which the
344
+ <em>agent</em> picks the destination URL turns page-content prompt injection into credential
345
+ exfiltration, and a check written into a script that already holds the plaintext in its own
346
+ environment is not a boundary — the script can simply not call it. That is what
347
+ <code>canonical_origin</code> is for: https-only, stored normalized
348
+ (<code>scheme://host[:port]</code>, no path/query/fragment/userinfo, host lowercased), so a
349
+ separate <em>out-of-process</em> runner that the agent does not author can pin a credential to
350
+ exactly one origin and check the live top-level frame before typing. That runner is
351
+ deliberately not shipped in this package. <code>totp_secret</code> must be base32 — a
352
+ malformed seed produces wrong codes that look exactly like a wrong password.</p>
336
353
  </section>
337
354
 
338
355
  <hr class="divider">
@@ -168,9 +168,10 @@
168
168
  <div class="step-grid">
169
169
  <div class="step-card">
170
170
  <span class="step-num">1</span><h4>Start the Oracle</h4>
171
- <pre><code>python oracle/oracle_server.py \
172
- --no-browser</code></pre>
173
- <p style="font-size: 12px; color: var(--text-dim); margin: 8px 0 0;">Prints the REST + MCP URLs and ensures an API key exists. The MCP server starts in a background thread.</p>
171
+ <pre><code>c3 oracle serve --no-browser
172
+ <span class="com"># or: run it at login, no terminal window</span>
173
+ c3 oracle serve --install</code></pre>
174
+ <p style="font-size: 12px; color: var(--text-dim); margin: 8px 0 0;">Prints the REST + MCP URLs and ensures an API key exists. The MCP server starts in a background thread. <code>--install</code> registers a windowless background service (Task Scheduler / launchd / systemd) and starts it now — the same buttons live in <strong>Hub → Settings → Oracle service</strong>.</p>
174
175
  </div>
175
176
  <div class="step-card">
176
177
  <span class="step-num">2</span><h4>Get the token</h4>
@@ -325,8 +326,14 @@ curl -X POST \
325
326
  <tr><td><code>c3 oracle api key</code></td> <td>Print just the token (generating one if needed)</td></tr>
326
327
  <tr><td><code>c3 oracle api rotate</code></td> <td>Replace the token with a fresh one</td></tr>
327
328
  <tr><td><code>c3 oracle api clear</code></td> <td>Delete the stored token from the keyring</td></tr>
329
+ <tr><td><code>c3 oracle serve</code></td> <td>Run the dashboard + discovery endpoints in this terminal (<code>--no-browser</code>, <code>--port</code>)</td></tr>
330
+ <tr><td><code>c3 oracle serve --install</code></td> <td>Register the Oracle as a login/startup service — no terminal window — and start it now. Windows: Task Scheduler (Run-key fallback); macOS: launchd; Linux: systemd user unit</td></tr>
331
+ <tr><td><code>c3 oracle serve --uninstall</code></td> <td>Remove the startup registration (a running Oracle keeps running)</td></tr>
332
+ <tr><td><code>c3 oracle serve --status</code></td> <td>Installed? Running? Port, bind host, URL, and the launcher log path</td></tr>
333
+ <tr><td><code>c3 oracle open</code></td> <td>Sign in to a running dashboard via a single-use URL (the hub's <strong>Open Oracle</strong> button does the same thing)</td></tr>
328
334
  </tbody>
329
335
  </table>
336
+ <p style="font-size: 12px; color: var(--text-dim); margin: 8px 0 0;">The Hub exposes the same controls under <strong>Settings → Oracle service</strong> (Install / Uninstall / Start / Stop / Open). Starting the Oracle from there also fills in the Hub's <em>Oracle URL</em> when it is empty, so the Open Oracle button appears in the top bar. That button opens a <strong>signed-in</strong> dashboard: it redeems the Oracle's owner-only bootstrap key for you. Reaching the dashboard by pasting its URL instead leaves it read-only — the page renders and the header looks healthy, but chat, Save and Test Ollama answer <code>401 unauthorized</code>.</p>
330
337
  </section>
331
338
 
332
339
  <hr class="divider">
@@ -373,6 +380,14 @@ curl -X POST \
373
380
  <td><code>The 'keyring' package is required</code></td>
374
381
  <td><code>pip install keyring</code> — a C3 dependency that may be missing if you upgraded without re-installing.</td>
375
382
  </tr>
383
+ <tr>
384
+ <td>Oracle is down after a reboot</td>
385
+ <td>Nothing restarts a terminal-launched Oracle. Register it once with <code>c3 oracle serve --install</code> (or Hub → Settings → Oracle service → Install); it then starts at login with no window. Startup problems land in <code>~/.c3/oracle/service.log</code> (the launcher) and <code>~/.c3/oracle/oracle.log</code> (the server).</td>
386
+ </tr>
387
+ <tr>
388
+ <td>Installed, but "stopped" right after login</td>
389
+ <td>If <code>bind_host</code> is a LAN/VPN address, the launcher waits up to 120 s for that address to come up before binding, and Task Scheduler retries a failed start three times a minute apart. Check <code>service.log</code> for <em>waiting for bind host</em>; if the address never appears, the Oracle starts anyway and fails to bind — fix the interface or set <code>bind_host</code> to <code>0.0.0.0</code>.</td>
390
+ </tr>
376
391
  </tbody>
377
392
  </table>
378
393
  </section>