code-context-control 2.89.1__tar.gz → 2.91.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 (446) hide show
  1. {code_context_control-2.89.1/code_context_control.egg-info → code_context_control-2.91.0}/PKG-INFO +2 -2
  2. {code_context_control-2.89.1 → code_context_control-2.91.0}/README.md +1 -1
  3. {code_context_control-2.89.1 → code_context_control-2.91.0}/cli/c3.py +30 -1
  4. {code_context_control-2.89.1 → code_context_control-2.91.0}/cli/commands/parser.py +9 -2
  5. {code_context_control-2.89.1 → code_context_control-2.91.0}/cli/guide/credentials.html +22 -5
  6. {code_context_control-2.89.1 → code_context_control-2.91.0}/cli/guide/oracle.html +18 -3
  7. {code_context_control-2.89.1 → code_context_control-2.91.0}/cli/hub_server.py +57 -0
  8. {code_context_control-2.89.1 → code_context_control-2.91.0}/cli/hub_ui/app.js +2 -1
  9. {code_context_control-2.89.1 → code_context_control-2.91.0}/cli/hub_ui/components/hub_credentials.js +26 -3
  10. {code_context_control-2.89.1 → code_context_control-2.91.0}/cli/hub_ui/components/settings_modal.js +148 -33
  11. {code_context_control-2.89.1 → code_context_control-2.91.0}/cli/mcp_server.py +9 -5
  12. {code_context_control-2.89.1 → code_context_control-2.91.0}/cli/tools/credentials.py +9 -1
  13. {code_context_control-2.89.1 → code_context_control-2.91.0}/cli/ui/components/credentials.js +26 -3
  14. {code_context_control-2.89.1 → code_context_control-2.91.0/code_context_control.egg-info}/PKG-INFO +2 -2
  15. {code_context_control-2.89.1 → code_context_control-2.91.0}/code_context_control.egg-info/SOURCES.txt +7 -0
  16. {code_context_control-2.89.1 → code_context_control-2.91.0}/oracle/oracle_server.py +17 -9
  17. {code_context_control-2.89.1 → code_context_control-2.91.0}/pyproject.toml +1 -1
  18. code_context_control-2.91.0/services/background_service.py +662 -0
  19. {code_context_control-2.89.1 → code_context_control-2.91.0}/services/claude_md.py +1 -1
  20. {code_context_control-2.89.1 → code_context_control-2.91.0}/services/credential_store.py +83 -3
  21. code_context_control-2.91.0/services/hub_service.py +78 -0
  22. code_context_control-2.91.0/services/oracle_service.py +141 -0
  23. code_context_control-2.91.0/tests/test_background_service.py +445 -0
  24. code_context_control-2.91.0/tests/test_credential_login_kind.py +191 -0
  25. code_context_control-2.91.0/tests/test_credential_ui_parity.py +146 -0
  26. code_context_control-2.91.0/tests/test_hub_oracle_service_routes.py +146 -0
  27. code_context_control-2.91.0/tests/test_oracle_health_probe.py +73 -0
  28. code_context_control-2.89.1/services/hub_service.py +0 -585
  29. {code_context_control-2.89.1 → code_context_control-2.91.0}/LICENSE +0 -0
  30. {code_context_control-2.89.1 → code_context_control-2.91.0}/cli/__init__.py +0 -0
  31. {code_context_control-2.89.1 → code_context_control-2.91.0}/cli/_hook_utils.py +0 -0
  32. {code_context_control-2.89.1 → code_context_control-2.91.0}/cli/commands/__init__.py +0 -0
  33. {code_context_control-2.89.1 → code_context_control-2.91.0}/cli/commands/common.py +0 -0
  34. {code_context_control-2.89.1 → code_context_control-2.91.0}/cli/docs.html +0 -0
  35. {code_context_control-2.89.1 → code_context_control-2.91.0}/cli/edits.html +0 -0
  36. {code_context_control-2.89.1 → code_context_control-2.91.0}/cli/guide/access.html +0 -0
  37. {code_context_control-2.89.1 → code_context_control-2.91.0}/cli/guide/bitbucket.html +0 -0
  38. {code_context_control-2.89.1 → code_context_control-2.91.0}/cli/guide/getting-started.html +0 -0
  39. {code_context_control-2.89.1 → code_context_control-2.91.0}/cli/guide/index.html +0 -0
  40. {code_context_control-2.89.1 → code_context_control-2.91.0}/cli/guide/masking.html +0 -0
  41. {code_context_control-2.89.1 → code_context_control-2.91.0}/cli/guide/shared.css +0 -0
  42. {code_context_control-2.89.1 → code_context_control-2.91.0}/cli/guide/tools.html +0 -0
  43. {code_context_control-2.89.1 → code_context_control-2.91.0}/cli/guide/workflow.html +0 -0
  44. {code_context_control-2.89.1 → code_context_control-2.91.0}/cli/hook_access_guard.py +0 -0
  45. {code_context_control-2.89.1 → code_context_control-2.91.0}/cli/hook_artifact.py +0 -0
  46. {code_context_control-2.89.1 → code_context_control-2.91.0}/cli/hook_auto_snapshot.py +0 -0
  47. {code_context_control-2.89.1 → code_context_control-2.91.0}/cli/hook_c3_signal.py +0 -0
  48. {code_context_control-2.89.1 → code_context_control-2.91.0}/cli/hook_c3read.py +0 -0
  49. {code_context_control-2.89.1 → code_context_control-2.91.0}/cli/hook_dispatch.py +0 -0
  50. {code_context_control-2.89.1 → code_context_control-2.91.0}/cli/hook_edit_ledger.py +0 -0
  51. {code_context_control-2.89.1 → code_context_control-2.91.0}/cli/hook_edit_unlock.py +0 -0
  52. {code_context_control-2.89.1 → code_context_control-2.91.0}/cli/hook_filter.py +0 -0
  53. {code_context_control-2.89.1 → code_context_control-2.91.0}/cli/hook_ghost_files.py +0 -0
  54. {code_context_control-2.89.1 → code_context_control-2.91.0}/cli/hook_pretool_enforce.py +0 -0
  55. {code_context_control-2.89.1 → code_context_control-2.91.0}/cli/hook_prompt_recall.py +0 -0
  56. {code_context_control-2.89.1 → code_context_control-2.91.0}/cli/hook_read.py +0 -0
  57. {code_context_control-2.89.1 → code_context_control-2.91.0}/cli/hook_session_stats.py +0 -0
  58. {code_context_control-2.89.1 → code_context_control-2.91.0}/cli/hook_terse_advisor.py +0 -0
  59. {code_context_control-2.89.1 → code_context_control-2.91.0}/cli/hub_ui/components/add_project.js +0 -0
  60. {code_context_control-2.89.1 → code_context_control-2.91.0}/cli/hub_ui/components/config_editor.js +0 -0
  61. {code_context_control-2.89.1 → code_context_control-2.91.0}/cli/hub_ui/components/drill_artifacts.js +0 -0
  62. {code_context_control-2.89.1 → code_context_control-2.91.0}/cli/hub_ui/components/drill_health.js +0 -0
  63. {code_context_control-2.89.1 → code_context_control-2.91.0}/cli/hub_ui/components/drill_panel.js +0 -0
  64. {code_context_control-2.89.1 → code_context_control-2.91.0}/cli/hub_ui/components/drill_subprojects.js +0 -0
  65. {code_context_control-2.89.1 → code_context_control-2.91.0}/cli/hub_ui/components/drill_tasks.js +0 -0
  66. {code_context_control-2.89.1 → code_context_control-2.91.0}/cli/hub_ui/components/drill_views.js +0 -0
  67. {code_context_control-2.89.1 → code_context_control-2.91.0}/cli/hub_ui/components/global_search.js +0 -0
  68. {code_context_control-2.89.1 → code_context_control-2.91.0}/cli/hub_ui/components/hub_ci.js +0 -0
  69. {code_context_control-2.89.1 → code_context_control-2.91.0}/cli/hub_ui/components/hub_enforcement.js +0 -0
  70. {code_context_control-2.89.1 → code_context_control-2.91.0}/cli/hub_ui/components/hub_locks.js +0 -0
  71. {code_context_control-2.89.1 → code_context_control-2.91.0}/cli/hub_ui/components/mcp_manager.js +0 -0
  72. {code_context_control-2.89.1 → code_context_control-2.91.0}/cli/hub_ui/components/modals.js +0 -0
  73. {code_context_control-2.89.1 → code_context_control-2.91.0}/cli/hub_ui/components/project_card.js +0 -0
  74. {code_context_control-2.89.1 → code_context_control-2.91.0}/cli/hub_ui/components/project_tree.js +0 -0
  75. {code_context_control-2.89.1 → code_context_control-2.91.0}/cli/hub_ui/components/session_drawer.js +0 -0
  76. {code_context_control-2.89.1 → code_context_control-2.91.0}/cli/hub_ui/components/sidebar.js +0 -0
  77. {code_context_control-2.89.1 → code_context_control-2.91.0}/cli/hub_ui/components/summary_bar.js +0 -0
  78. {code_context_control-2.89.1 → code_context_control-2.91.0}/cli/hub_ui/components/task_board.js +0 -0
  79. {code_context_control-2.89.1 → code_context_control-2.91.0}/cli/hub_ui/components/toasts.js +0 -0
  80. {code_context_control-2.89.1 → code_context_control-2.91.0}/cli/hub_ui/components/topbar.js +0 -0
  81. {code_context_control-2.89.1 → code_context_control-2.91.0}/cli/hub_ui/state.js +0 -0
  82. {code_context_control-2.89.1 → code_context_control-2.91.0}/cli/hub_ui.html +0 -0
  83. {code_context_control-2.89.1 → code_context_control-2.91.0}/cli/mcp_proxy.py +0 -0
  84. {code_context_control-2.89.1 → code_context_control-2.91.0}/cli/progress.py +0 -0
  85. {code_context_control-2.89.1 → code_context_control-2.91.0}/cli/server.py +0 -0
  86. {code_context_control-2.89.1 → code_context_control-2.91.0}/cli/tools/__init__.py +0 -0
  87. {code_context_control-2.89.1 → code_context_control-2.91.0}/cli/tools/_grants.py +0 -0
  88. {code_context_control-2.89.1 → code_context_control-2.91.0}/cli/tools/_helpers.py +0 -0
  89. {code_context_control-2.89.1 → code_context_control-2.91.0}/cli/tools/agent.py +0 -0
  90. {code_context_control-2.89.1 → code_context_control-2.91.0}/cli/tools/artifacts.py +0 -0
  91. {code_context_control-2.89.1 → code_context_control-2.91.0}/cli/tools/bitbucket.py +0 -0
  92. {code_context_control-2.89.1 → code_context_control-2.91.0}/cli/tools/ci.py +0 -0
  93. {code_context_control-2.89.1 → code_context_control-2.91.0}/cli/tools/compress.py +0 -0
  94. {code_context_control-2.89.1 → code_context_control-2.91.0}/cli/tools/delegate.py +0 -0
  95. {code_context_control-2.89.1 → code_context_control-2.91.0}/cli/tools/edit.py +0 -0
  96. {code_context_control-2.89.1 → code_context_control-2.91.0}/cli/tools/edit_verify.py +0 -0
  97. {code_context_control-2.89.1 → code_context_control-2.91.0}/cli/tools/edits.py +0 -0
  98. {code_context_control-2.89.1 → code_context_control-2.91.0}/cli/tools/federate.py +0 -0
  99. {code_context_control-2.89.1 → code_context_control-2.91.0}/cli/tools/filter.py +0 -0
  100. {code_context_control-2.89.1 → code_context_control-2.91.0}/cli/tools/impact.py +0 -0
  101. {code_context_control-2.89.1 → code_context_control-2.91.0}/cli/tools/jira.py +0 -0
  102. {code_context_control-2.89.1 → code_context_control-2.91.0}/cli/tools/locks.py +0 -0
  103. {code_context_control-2.89.1 → code_context_control-2.91.0}/cli/tools/memory.py +0 -0
  104. {code_context_control-2.89.1 → code_context_control-2.91.0}/cli/tools/override.py +0 -0
  105. {code_context_control-2.89.1 → code_context_control-2.91.0}/cli/tools/project.py +0 -0
  106. {code_context_control-2.89.1 → code_context_control-2.91.0}/cli/tools/read.py +0 -0
  107. {code_context_control-2.89.1 → code_context_control-2.91.0}/cli/tools/search.py +0 -0
  108. {code_context_control-2.89.1 → code_context_control-2.91.0}/cli/tools/session.py +0 -0
  109. {code_context_control-2.89.1 → code_context_control-2.91.0}/cli/tools/shell.py +0 -0
  110. {code_context_control-2.89.1 → code_context_control-2.91.0}/cli/tools/status.py +0 -0
  111. {code_context_control-2.89.1 → code_context_control-2.91.0}/cli/tools/tasks.py +0 -0
  112. {code_context_control-2.89.1 → code_context_control-2.91.0}/cli/tools/validate.py +0 -0
  113. {code_context_control-2.89.1 → code_context_control-2.91.0}/cli/ui/api.js +0 -0
  114. {code_context_control-2.89.1 → code_context_control-2.91.0}/cli/ui/app.js +0 -0
  115. {code_context_control-2.89.1 → code_context_control-2.91.0}/cli/ui/components/access.js +0 -0
  116. {code_context_control-2.89.1 → code_context_control-2.91.0}/cli/ui/components/bitbucket.js +0 -0
  117. {code_context_control-2.89.1 → code_context_control-2.91.0}/cli/ui/components/chat.js +0 -0
  118. {code_context_control-2.89.1 → code_context_control-2.91.0}/cli/ui/components/dashboard.js +0 -0
  119. {code_context_control-2.89.1 → code_context_control-2.91.0}/cli/ui/components/edits.js +0 -0
  120. {code_context_control-2.89.1 → code_context_control-2.91.0}/cli/ui/components/enforcement.js +0 -0
  121. {code_context_control-2.89.1 → code_context_control-2.91.0}/cli/ui/components/instructions.js +0 -0
  122. {code_context_control-2.89.1 → code_context_control-2.91.0}/cli/ui/components/jira.js +0 -0
  123. {code_context_control-2.89.1 → code_context_control-2.91.0}/cli/ui/components/memory.js +0 -0
  124. {code_context_control-2.89.1 → code_context_control-2.91.0}/cli/ui/components/sessions.js +0 -0
  125. {code_context_control-2.89.1 → code_context_control-2.91.0}/cli/ui/components/settings.js +0 -0
  126. {code_context_control-2.89.1 → code_context_control-2.91.0}/cli/ui/components/sidebar.js +0 -0
  127. {code_context_control-2.89.1 → code_context_control-2.91.0}/cli/ui/components/tasks.js +0 -0
  128. {code_context_control-2.89.1 → code_context_control-2.91.0}/cli/ui/icons.js +0 -0
  129. {code_context_control-2.89.1 → code_context_control-2.91.0}/cli/ui/pm_shared.js +0 -0
  130. {code_context_control-2.89.1 → code_context_control-2.91.0}/cli/ui/shared.js +0 -0
  131. {code_context_control-2.89.1 → code_context_control-2.91.0}/cli/ui/theme.js +0 -0
  132. {code_context_control-2.89.1 → code_context_control-2.91.0}/cli/ui.html +0 -0
  133. {code_context_control-2.89.1 → code_context_control-2.91.0}/cli/ui_legacy.html +0 -0
  134. {code_context_control-2.89.1 → code_context_control-2.91.0}/cli/ui_nano.html +0 -0
  135. {code_context_control-2.89.1 → code_context_control-2.91.0}/code_context_control.egg-info/dependency_links.txt +0 -0
  136. {code_context_control-2.89.1 → code_context_control-2.91.0}/code_context_control.egg-info/entry_points.txt +0 -0
  137. {code_context_control-2.89.1 → code_context_control-2.91.0}/code_context_control.egg-info/requires.txt +0 -0
  138. {code_context_control-2.89.1 → code_context_control-2.91.0}/code_context_control.egg-info/top_level.txt +0 -0
  139. {code_context_control-2.89.1 → code_context_control-2.91.0}/core/__init__.py +0 -0
  140. {code_context_control-2.89.1 → code_context_control-2.91.0}/core/config.py +0 -0
  141. {code_context_control-2.89.1 → code_context_control-2.91.0}/core/ide.py +0 -0
  142. {code_context_control-2.89.1 → code_context_control-2.91.0}/core/mcp_toml.py +0 -0
  143. {code_context_control-2.89.1 → code_context_control-2.91.0}/core/web_security.py +0 -0
  144. {code_context_control-2.89.1 → code_context_control-2.91.0}/oracle/__init__.py +0 -0
  145. {code_context_control-2.89.1 → code_context_control-2.91.0}/oracle/config.py +0 -0
  146. {code_context_control-2.89.1 → code_context_control-2.91.0}/oracle/mcp_oracle.py +0 -0
  147. {code_context_control-2.89.1 → code_context_control-2.91.0}/oracle/oracle_ui.html +0 -0
  148. {code_context_control-2.89.1 → code_context_control-2.91.0}/oracle/services/__init__.py +0 -0
  149. {code_context_control-2.89.1 → code_context_control-2.91.0}/oracle/services/activity_reporter.py +0 -0
  150. {code_context_control-2.89.1 → code_context_control-2.91.0}/oracle/services/api_auth.py +0 -0
  151. {code_context_control-2.89.1 → code_context_control-2.91.0}/oracle/services/c3_bridge.py +0 -0
  152. {code_context_control-2.89.1 → code_context_control-2.91.0}/oracle/services/chat_engine.py +0 -0
  153. {code_context_control-2.89.1 → code_context_control-2.91.0}/oracle/services/chat_poll.py +0 -0
  154. {code_context_control-2.89.1 → code_context_control-2.91.0}/oracle/services/chat_store.py +0 -0
  155. {code_context_control-2.89.1 → code_context_control-2.91.0}/oracle/services/cross_memory.py +0 -0
  156. {code_context_control-2.89.1 → code_context_control-2.91.0}/oracle/services/discovery_audit.py +0 -0
  157. {code_context_control-2.89.1 → code_context_control-2.91.0}/oracle/services/federated_graph.py +0 -0
  158. {code_context_control-2.89.1 → code_context_control-2.91.0}/oracle/services/health_checker.py +0 -0
  159. {code_context_control-2.89.1 → code_context_control-2.91.0}/oracle/services/insight_engine.py +0 -0
  160. {code_context_control-2.89.1 → code_context_control-2.91.0}/oracle/services/local_session.py +0 -0
  161. {code_context_control-2.89.1 → code_context_control-2.91.0}/oracle/services/memory_reader.py +0 -0
  162. {code_context_control-2.89.1 → code_context_control-2.91.0}/oracle/services/memory_writer.py +0 -0
  163. {code_context_control-2.89.1 → code_context_control-2.91.0}/oracle/services/mobile_api.py +0 -0
  164. {code_context_control-2.89.1 → code_context_control-2.91.0}/oracle/services/project_scanner.py +0 -0
  165. {code_context_control-2.89.1 → code_context_control-2.91.0}/oracle/services/review_agent.py +0 -0
  166. {code_context_control-2.89.1 → code_context_control-2.91.0}/oracle/services/tool_executor.py +0 -0
  167. {code_context_control-2.89.1 → code_context_control-2.91.0}/oracle/services/tool_registry.py +0 -0
  168. {code_context_control-2.89.1 → code_context_control-2.91.0}/oracle/ui/activity.js +0 -0
  169. {code_context_control-2.89.1 → code_context_control-2.91.0}/oracle/ui/agents.js +0 -0
  170. {code_context_control-2.89.1 → code_context_control-2.91.0}/oracle/ui/app.js +0 -0
  171. {code_context_control-2.89.1 → code_context_control-2.91.0}/oracle/ui/busy.js +0 -0
  172. {code_context_control-2.89.1 → code_context_control-2.91.0}/oracle/ui/chat/conversations.js +0 -0
  173. {code_context_control-2.89.1 → code_context_control-2.91.0}/oracle/ui/chat/input.js +0 -0
  174. {code_context_control-2.89.1 → code_context_control-2.91.0}/oracle/ui/chat/markdown.js +0 -0
  175. {code_context_control-2.89.1 → code_context_control-2.91.0}/oracle/ui/chat/send.js +0 -0
  176. {code_context_control-2.89.1 → code_context_control-2.91.0}/oracle/ui/chat/stream_renderer.js +0 -0
  177. {code_context_control-2.89.1 → code_context_control-2.91.0}/oracle/ui/chat/toolbar.js +0 -0
  178. {code_context_control-2.89.1 → code_context_control-2.91.0}/oracle/ui/core.js +0 -0
  179. {code_context_control-2.89.1 → code_context_control-2.91.0}/oracle/ui/crossgraph.js +0 -0
  180. {code_context_control-2.89.1 → code_context_control-2.91.0}/oracle/ui/header.js +0 -0
  181. {code_context_control-2.89.1 → code_context_control-2.91.0}/oracle/ui/insights.js +0 -0
  182. {code_context_control-2.89.1 → code_context_control-2.91.0}/oracle/ui/projects.js +0 -0
  183. {code_context_control-2.89.1 → code_context_control-2.91.0}/oracle/ui/qrcode.js +0 -0
  184. {code_context_control-2.89.1 → code_context_control-2.91.0}/oracle/ui/settings.js +0 -0
  185. {code_context_control-2.89.1 → code_context_control-2.91.0}/oracle/ui/suggestions.js +0 -0
  186. {code_context_control-2.89.1 → code_context_control-2.91.0}/oracle/ui/theme_tabs.js +0 -0
  187. {code_context_control-2.89.1 → code_context_control-2.91.0}/services/__init__.py +0 -0
  188. {code_context_control-2.89.1 → code_context_control-2.91.0}/services/access_guard.py +0 -0
  189. {code_context_control-2.89.1 → code_context_control-2.91.0}/services/access_telemetry.py +0 -0
  190. {code_context_control-2.89.1 → code_context_control-2.91.0}/services/activity_log.py +0 -0
  191. {code_context_control-2.89.1 → code_context_control-2.91.0}/services/agent_base.py +0 -0
  192. {code_context_control-2.89.1 → code_context_control-2.91.0}/services/agent_locks.py +0 -0
  193. {code_context_control-2.89.1 → code_context_control-2.91.0}/services/agents.py +0 -0
  194. {code_context_control-2.89.1 → code_context_control-2.91.0}/services/artifact_defs.py +0 -0
  195. {code_context_control-2.89.1 → code_context_control-2.91.0}/services/artifact_store.py +0 -0
  196. {code_context_control-2.89.1 → code_context_control-2.91.0}/services/auto_memory.py +0 -0
  197. {code_context_control-2.89.1 → code_context_control-2.91.0}/services/bench/__init__.py +0 -0
  198. {code_context_control-2.89.1 → code_context_control-2.91.0}/services/bench/external/__init__.py +0 -0
  199. {code_context_control-2.89.1 → code_context_control-2.91.0}/services/bench/external/aider_polyglot.py +0 -0
  200. {code_context_control-2.89.1 → code_context_control-2.91.0}/services/bench/external/swe_bench.py +0 -0
  201. {code_context_control-2.89.1 → code_context_control-2.91.0}/services/benchmark_dashboard.py +0 -0
  202. {code_context_control-2.89.1 → code_context_control-2.91.0}/services/bitbucket_client.py +0 -0
  203. {code_context_control-2.89.1 → code_context_control-2.91.0}/services/bitbucket_credentials.py +0 -0
  204. {code_context_control-2.89.1 → code_context_control-2.91.0}/services/ci_act.py +0 -0
  205. {code_context_control-2.89.1 → code_context_control-2.91.0}/services/ci_cache.py +0 -0
  206. {code_context_control-2.89.1 → code_context_control-2.91.0}/services/ci_expr.py +0 -0
  207. {code_context_control-2.89.1 → code_context_control-2.91.0}/services/ci_failures.py +0 -0
  208. {code_context_control-2.89.1 → code_context_control-2.91.0}/services/ci_github.py +0 -0
  209. {code_context_control-2.89.1 → code_context_control-2.91.0}/services/ci_impact.py +0 -0
  210. {code_context_control-2.89.1 → code_context_control-2.91.0}/services/ci_intel.py +0 -0
  211. {code_context_control-2.89.1 → code_context_control-2.91.0}/services/ci_runner.py +0 -0
  212. {code_context_control-2.89.1 → code_context_control-2.91.0}/services/ci_workflow.py +0 -0
  213. {code_context_control-2.89.1 → code_context_control-2.91.0}/services/circuit_breaker.py +0 -0
  214. {code_context_control-2.89.1 → code_context_control-2.91.0}/services/compressor.py +0 -0
  215. {code_context_control-2.89.1 → code_context_control-2.91.0}/services/context_snapshot.py +0 -0
  216. {code_context_control-2.89.1 → code_context_control-2.91.0}/services/conversation_store.py +0 -0
  217. {code_context_control-2.89.1 → code_context_control-2.91.0}/services/cred_telemetry.py +0 -0
  218. {code_context_control-2.89.1 → code_context_control-2.91.0}/services/doc_index.py +0 -0
  219. {code_context_control-2.89.1 → code_context_control-2.91.0}/services/e2e_benchmark.py +0 -0
  220. {code_context_control-2.89.1 → code_context_control-2.91.0}/services/e2e_evaluator.py +0 -0
  221. {code_context_control-2.89.1 → code_context_control-2.91.0}/services/e2e_tasks.py +0 -0
  222. {code_context_control-2.89.1 → code_context_control-2.91.0}/services/edit_ledger.py +0 -0
  223. {code_context_control-2.89.1 → code_context_control-2.91.0}/services/embedding_index.py +0 -0
  224. {code_context_control-2.89.1 → code_context_control-2.91.0}/services/enforcement_policy.py +0 -0
  225. {code_context_control-2.89.1 → code_context_control-2.91.0}/services/error_reporting.py +0 -0
  226. {code_context_control-2.89.1 → code_context_control-2.91.0}/services/file_memory.py +0 -0
  227. {code_context_control-2.89.1 → code_context_control-2.91.0}/services/git_context.py +0 -0
  228. {code_context_control-2.89.1 → code_context_control-2.91.0}/services/indexer.py +0 -0
  229. {code_context_control-2.89.1 → code_context_control-2.91.0}/services/jira_client.py +0 -0
  230. {code_context_control-2.89.1 → code_context_control-2.91.0}/services/jira_cloud.py +0 -0
  231. {code_context_control-2.89.1 → code_context_control-2.91.0}/services/jira_credentials.py +0 -0
  232. {code_context_control-2.89.1 → code_context_control-2.91.0}/services/jira_data_center.py +0 -0
  233. {code_context_control-2.89.1 → code_context_control-2.91.0}/services/jira_links.py +0 -0
  234. {code_context_control-2.89.1 → code_context_control-2.91.0}/services/mask_activation.py +0 -0
  235. {code_context_control-2.89.1 → code_context_control-2.91.0}/services/mask_mirror.py +0 -0
  236. {code_context_control-2.89.1 → code_context_control-2.91.0}/services/mask_presets.py +0 -0
  237. {code_context_control-2.89.1 → code_context_control-2.91.0}/services/memory.py +0 -0
  238. {code_context_control-2.89.1 → code_context_control-2.91.0}/services/memory_consolidator.py +0 -0
  239. {code_context_control-2.89.1 → code_context_control-2.91.0}/services/memory_distiller.py +0 -0
  240. {code_context_control-2.89.1 → code_context_control-2.91.0}/services/memory_graph.py +0 -0
  241. {code_context_control-2.89.1 → code_context_control-2.91.0}/services/memory_grounder.py +0 -0
  242. {code_context_control-2.89.1 → code_context_control-2.91.0}/services/memory_queue.py +0 -0
  243. {code_context_control-2.89.1 → code_context_control-2.91.0}/services/memory_scorer.py +0 -0
  244. {code_context_control-2.89.1 → code_context_control-2.91.0}/services/metrics.py +0 -0
  245. {code_context_control-2.89.1 → code_context_control-2.91.0}/services/notifications.py +0 -0
  246. {code_context_control-2.89.1 → code_context_control-2.91.0}/services/ollama_bridge.py +0 -0
  247. {code_context_control-2.89.1 → code_context_control-2.91.0}/services/ollama_client.py +0 -0
  248. {code_context_control-2.89.1 → code_context_control-2.91.0}/services/ollama_credentials.py +0 -0
  249. {code_context_control-2.89.1 → code_context_control-2.91.0}/services/output_filter.py +0 -0
  250. {code_context_control-2.89.1 → code_context_control-2.91.0}/services/override_grants.py +0 -0
  251. {code_context_control-2.89.1 → code_context_control-2.91.0}/services/override_policy.py +0 -0
  252. {code_context_control-2.89.1 → code_context_control-2.91.0}/services/override_requests.py +0 -0
  253. {code_context_control-2.89.1 → code_context_control-2.91.0}/services/override_wake.py +0 -0
  254. {code_context_control-2.89.1 → code_context_control-2.91.0}/services/parser.py +0 -0
  255. {code_context_control-2.89.1 → code_context_control-2.91.0}/services/project_manager.py +0 -0
  256. {code_context_control-2.89.1 → code_context_control-2.91.0}/services/project_runtime.py +0 -0
  257. {code_context_control-2.89.1 → code_context_control-2.91.0}/services/protocol.py +0 -0
  258. {code_context_control-2.89.1 → code_context_control-2.91.0}/services/proxy_state.py +0 -0
  259. {code_context_control-2.89.1 → code_context_control-2.91.0}/services/repo_map.py +0 -0
  260. {code_context_control-2.89.1 → code_context_control-2.91.0}/services/retention.py +0 -0
  261. {code_context_control-2.89.1 → code_context_control-2.91.0}/services/retrieval_broker.py +0 -0
  262. {code_context_control-2.89.1 → code_context_control-2.91.0}/services/router.py +0 -0
  263. {code_context_control-2.89.1 → code_context_control-2.91.0}/services/runtime.py +0 -0
  264. {code_context_control-2.89.1 → code_context_control-2.91.0}/services/scanner.py +0 -0
  265. {code_context_control-2.89.1 → code_context_control-2.91.0}/services/session_benchmark.py +0 -0
  266. {code_context_control-2.89.1 → code_context_control-2.91.0}/services/session_manager.py +0 -0
  267. {code_context_control-2.89.1 → code_context_control-2.91.0}/services/session_preloader.py +0 -0
  268. {code_context_control-2.89.1 → code_context_control-2.91.0}/services/subprojects.py +0 -0
  269. {code_context_control-2.89.1 → code_context_control-2.91.0}/services/task_store.py +0 -0
  270. {code_context_control-2.89.1 → code_context_control-2.91.0}/services/telemetry.py +0 -0
  271. {code_context_control-2.89.1 → code_context_control-2.91.0}/services/text_index.py +0 -0
  272. {code_context_control-2.89.1 → code_context_control-2.91.0}/services/time_tracker.py +0 -0
  273. {code_context_control-2.89.1 → code_context_control-2.91.0}/services/tool_classifier.py +0 -0
  274. {code_context_control-2.89.1 → code_context_control-2.91.0}/services/transcript_index.py +0 -0
  275. {code_context_control-2.89.1 → code_context_control-2.91.0}/services/validation_cache.py +0 -0
  276. {code_context_control-2.89.1 → code_context_control-2.91.0}/services/vector_store.py +0 -0
  277. {code_context_control-2.89.1 → code_context_control-2.91.0}/services/watcher.py +0 -0
  278. {code_context_control-2.89.1 → code_context_control-2.91.0}/services/win_subprocess.py +0 -0
  279. {code_context_control-2.89.1 → code_context_control-2.91.0}/setup.cfg +0 -0
  280. {code_context_control-2.89.1 → code_context_control-2.91.0}/tests/test_access_builtin_optout.py +0 -0
  281. {code_context_control-2.89.1 → code_context_control-2.91.0}/tests/test_access_guard.py +0 -0
  282. {code_context_control-2.89.1 → code_context_control-2.91.0}/tests/test_access_guard_meta.py +0 -0
  283. {code_context_control-2.89.1 → code_context_control-2.91.0}/tests/test_access_guard_shell_project.py +0 -0
  284. {code_context_control-2.89.1 → code_context_control-2.91.0}/tests/test_access_guard_surfaces.py +0 -0
  285. {code_context_control-2.89.1 → code_context_control-2.91.0}/tests/test_access_guard_wiring.py +0 -0
  286. {code_context_control-2.89.1 → code_context_control-2.91.0}/tests/test_activity_reporter.py +0 -0
  287. {code_context_control-2.89.1 → code_context_control-2.91.0}/tests/test_agent_locks.py +0 -0
  288. {code_context_control-2.89.1 → code_context_control-2.91.0}/tests/test_aider_polyglot.py +0 -0
  289. {code_context_control-2.89.1 → code_context_control-2.91.0}/tests/test_antigravity_transition.py +0 -0
  290. {code_context_control-2.89.1 → code_context_control-2.91.0}/tests/test_artifact_store.py +0 -0
  291. {code_context_control-2.89.1 → code_context_control-2.91.0}/tests/test_artifact_tool.py +0 -0
  292. {code_context_control-2.89.1 → code_context_control-2.91.0}/tests/test_bitbucket_cli_smoke.py +0 -0
  293. {code_context_control-2.89.1 → code_context_control-2.91.0}/tests/test_bitbucket_client.py +0 -0
  294. {code_context_control-2.89.1 → code_context_control-2.91.0}/tests/test_bitbucket_config_fallback.py +0 -0
  295. {code_context_control-2.89.1 → code_context_control-2.91.0}/tests/test_bitbucket_credentials.py +0 -0
  296. {code_context_control-2.89.1 → code_context_control-2.91.0}/tests/test_bitbucket_tool.py +0 -0
  297. {code_context_control-2.89.1 → code_context_control-2.91.0}/tests/test_c3_bridge_project_artifacts.py +0 -0
  298. {code_context_control-2.89.1 → code_context_control-2.91.0}/tests/test_c3_shell.py +0 -0
  299. {code_context_control-2.89.1 → code_context_control-2.91.0}/tests/test_chat_poll.py +0 -0
  300. {code_context_control-2.89.1 → code_context_control-2.91.0}/tests/test_ci_act.py +0 -0
  301. {code_context_control-2.89.1 → code_context_control-2.91.0}/tests/test_ci_cache.py +0 -0
  302. {code_context_control-2.89.1 → code_context_control-2.91.0}/tests/test_ci_expr.py +0 -0
  303. {code_context_control-2.89.1 → code_context_control-2.91.0}/tests/test_ci_impact.py +0 -0
  304. {code_context_control-2.89.1 → code_context_control-2.91.0}/tests/test_ci_intel.py +0 -0
  305. {code_context_control-2.89.1 → code_context_control-2.91.0}/tests/test_ci_runner.py +0 -0
  306. {code_context_control-2.89.1 → code_context_control-2.91.0}/tests/test_ci_workflow.py +0 -0
  307. {code_context_control-2.89.1 → code_context_control-2.91.0}/tests/test_circuit_breaker.py +0 -0
  308. {code_context_control-2.89.1 → code_context_control-2.91.0}/tests/test_claude_md_merge.py +0 -0
  309. {code_context_control-2.89.1 → code_context_control-2.91.0}/tests/test_cli_smoke.py +0 -0
  310. {code_context_control-2.89.1 → code_context_control-2.91.0}/tests/test_compressor_large_file.py +0 -0
  311. {code_context_control-2.89.1 → code_context_control-2.91.0}/tests/test_cred_telemetry.py +0 -0
  312. {code_context_control-2.89.1 → code_context_control-2.91.0}/tests/test_credential_store.py +0 -0
  313. {code_context_control-2.89.1 → code_context_control-2.91.0}/tests/test_credentials_routes.py +0 -0
  314. {code_context_control-2.89.1 → code_context_control-2.91.0}/tests/test_credentials_tool.py +0 -0
  315. {code_context_control-2.89.1 → code_context_control-2.91.0}/tests/test_creds_cli_smoke.py +0 -0
  316. {code_context_control-2.89.1 → code_context_control-2.91.0}/tests/test_delegate_cascade.py +0 -0
  317. {code_context_control-2.89.1 → code_context_control-2.91.0}/tests/test_delegate_version_probe.py +0 -0
  318. {code_context_control-2.89.1 → code_context_control-2.91.0}/tests/test_e2e_benchmark.py +0 -0
  319. {code_context_control-2.89.1 → code_context_control-2.91.0}/tests/test_edit_ledger_deadline.py +0 -0
  320. {code_context_control-2.89.1 → code_context_control-2.91.0}/tests/test_edit_ledger_hook.py +0 -0
  321. {code_context_control-2.89.1 → code_context_control-2.91.0}/tests/test_edit_locking.py +0 -0
  322. {code_context_control-2.89.1 → code_context_control-2.91.0}/tests/test_edit_normalization.py +0 -0
  323. {code_context_control-2.89.1 → code_context_control-2.91.0}/tests/test_edit_verify.py +0 -0
  324. {code_context_control-2.89.1 → code_context_control-2.91.0}/tests/test_embedding_index_deadlock.py +0 -0
  325. {code_context_control-2.89.1 → code_context_control-2.91.0}/tests/test_enforcement_flip.py +0 -0
  326. {code_context_control-2.89.1 → code_context_control-2.91.0}/tests/test_enforcement_policy.py +0 -0
  327. {code_context_control-2.89.1 → code_context_control-2.91.0}/tests/test_enforcement_routes.py +0 -0
  328. {code_context_control-2.89.1 → code_context_control-2.91.0}/tests/test_federated_graph.py +0 -0
  329. {code_context_control-2.89.1 → code_context_control-2.91.0}/tests/test_filter_backoff.py +0 -0
  330. {code_context_control-2.89.1 → code_context_control-2.91.0}/tests/test_ghost_files.py +0 -0
  331. {code_context_control-2.89.1 → code_context_control-2.91.0}/tests/test_ghost_generation.py +0 -0
  332. {code_context_control-2.89.1 → code_context_control-2.91.0}/tests/test_git_branch_awareness.py +0 -0
  333. {code_context_control-2.89.1 → code_context_control-2.91.0}/tests/test_hook_access_guard.py +0 -0
  334. {code_context_control-2.89.1 → code_context_control-2.91.0}/tests/test_hook_codex_compat.py +0 -0
  335. {code_context_control-2.89.1 → code_context_control-2.91.0}/tests/test_hook_dispatch.py +0 -0
  336. {code_context_control-2.89.1 → code_context_control-2.91.0}/tests/test_hook_pretool_enforce.py +0 -0
  337. {code_context_control-2.89.1 → code_context_control-2.91.0}/tests/test_hook_prompt_recall.py +0 -0
  338. {code_context_control-2.89.1 → code_context_control-2.91.0}/tests/test_hook_smoke.py +0 -0
  339. {code_context_control-2.89.1 → code_context_control-2.91.0}/tests/test_hook_state.py +0 -0
  340. {code_context_control-2.89.1 → code_context_control-2.91.0}/tests/test_hook_utf8_stdio.py +0 -0
  341. {code_context_control-2.89.1 → code_context_control-2.91.0}/tests/test_hub_credentials_route.py +0 -0
  342. {code_context_control-2.89.1 → code_context_control-2.91.0}/tests/test_hub_credentials_routes_write.py +0 -0
  343. {code_context_control-2.89.1 → code_context_control-2.91.0}/tests/test_hub_enforcement_routes.py +0 -0
  344. {code_context_control-2.89.1 → code_context_control-2.91.0}/tests/test_hub_inspect_api.py +0 -0
  345. {code_context_control-2.89.1 → code_context_control-2.91.0}/tests/test_hub_locks_routes.py +0 -0
  346. {code_context_control-2.89.1 → code_context_control-2.91.0}/tests/test_hub_server_smoke.py +0 -0
  347. {code_context_control-2.89.1 → code_context_control-2.91.0}/tests/test_hub_subproject_links.py +0 -0
  348. {code_context_control-2.89.1 → code_context_control-2.91.0}/tests/test_ide_workflow_adaptation.py +0 -0
  349. {code_context_control-2.89.1 → code_context_control-2.91.0}/tests/test_init_scan.py +0 -0
  350. {code_context_control-2.89.1 → code_context_control-2.91.0}/tests/test_install_mcp_entrypoint.py +0 -0
  351. {code_context_control-2.89.1 → code_context_control-2.91.0}/tests/test_jira_cli_smoke.py +0 -0
  352. {code_context_control-2.89.1 → code_context_control-2.91.0}/tests/test_jira_client.py +0 -0
  353. {code_context_control-2.89.1 → code_context_control-2.91.0}/tests/test_jira_config_fallback.py +0 -0
  354. {code_context_control-2.89.1 → code_context_control-2.91.0}/tests/test_jira_credentials.py +0 -0
  355. {code_context_control-2.89.1 → code_context_control-2.91.0}/tests/test_jira_links.py +0 -0
  356. {code_context_control-2.89.1 → code_context_control-2.91.0}/tests/test_jira_routes.py +0 -0
  357. {code_context_control-2.89.1 → code_context_control-2.91.0}/tests/test_jira_tool.py +0 -0
  358. {code_context_control-2.89.1 → code_context_control-2.91.0}/tests/test_lazy_store_init.py +0 -0
  359. {code_context_control-2.89.1 → code_context_control-2.91.0}/tests/test_mask_guard.py +0 -0
  360. {code_context_control-2.89.1 → code_context_control-2.91.0}/tests/test_mask_routes.py +0 -0
  361. {code_context_control-2.89.1 → code_context_control-2.91.0}/tests/test_mask_surfaces.py +0 -0
  362. {code_context_control-2.89.1 → code_context_control-2.91.0}/tests/test_mcp_host_guard.py +0 -0
  363. {code_context_control-2.89.1 → code_context_control-2.91.0}/tests/test_mcp_memory_timeout.py +0 -0
  364. {code_context_control-2.89.1 → code_context_control-2.91.0}/tests/test_mcp_server_smoke.py +0 -0
  365. {code_context_control-2.89.1 → code_context_control-2.91.0}/tests/test_mcp_toml.py +0 -0
  366. {code_context_control-2.89.1 → code_context_control-2.91.0}/tests/test_memory_distiller.py +0 -0
  367. {code_context_control-2.89.1 → code_context_control-2.91.0}/tests/test_memory_graph_api.py +0 -0
  368. {code_context_control-2.89.1 → code_context_control-2.91.0}/tests/test_memory_queue.py +0 -0
  369. {code_context_control-2.89.1 → code_context_control-2.91.0}/tests/test_memory_system.py +0 -0
  370. {code_context_control-2.89.1 → code_context_control-2.91.0}/tests/test_mobile_api.py +0 -0
  371. {code_context_control-2.89.1 → code_context_control-2.91.0}/tests/test_mobile_extras.py +0 -0
  372. {code_context_control-2.89.1 → code_context_control-2.91.0}/tests/test_mobile_override_routes.py +0 -0
  373. {code_context_control-2.89.1 → code_context_control-2.91.0}/tests/test_mobile_security_api.py +0 -0
  374. {code_context_control-2.89.1 → code_context_control-2.91.0}/tests/test_no_stale_model_pins.py +0 -0
  375. {code_context_control-2.89.1 → code_context_control-2.91.0}/tests/test_notification_dedup.py +0 -0
  376. {code_context_control-2.89.1 → code_context_control-2.91.0}/tests/test_notification_discipline.py +0 -0
  377. {code_context_control-2.89.1 → code_context_control-2.91.0}/tests/test_ollama_credentials.py +0 -0
  378. {code_context_control-2.89.1 → code_context_control-2.91.0}/tests/test_oracle_api_auth.py +0 -0
  379. {code_context_control-2.89.1 → code_context_control-2.91.0}/tests/test_oracle_apikey_api.py +0 -0
  380. {code_context_control-2.89.1 → code_context_control-2.91.0}/tests/test_oracle_c3_bridge.py +0 -0
  381. {code_context_control-2.89.1 → code_context_control-2.91.0}/tests/test_oracle_chat_engine.py +0 -0
  382. {code_context_control-2.89.1 → code_context_control-2.91.0}/tests/test_oracle_chat_store.py +0 -0
  383. {code_context_control-2.89.1 → code_context_control-2.91.0}/tests/test_oracle_discovery_api.py +0 -0
  384. {code_context_control-2.89.1 → code_context_control-2.91.0}/tests/test_oracle_discovery_audit.py +0 -0
  385. {code_context_control-2.89.1 → code_context_control-2.91.0}/tests/test_oracle_local_auth.py +0 -0
  386. {code_context_control-2.89.1 → code_context_control-2.91.0}/tests/test_oracle_ollama_bridge.py +0 -0
  387. {code_context_control-2.89.1 → code_context_control-2.91.0}/tests/test_oracle_scanner_cache.py +0 -0
  388. {code_context_control-2.89.1 → code_context_control-2.91.0}/tests/test_oracle_security_fixes.py +0 -0
  389. {code_context_control-2.89.1 → code_context_control-2.91.0}/tests/test_oracle_session_bootstrap.py +0 -0
  390. {code_context_control-2.89.1 → code_context_control-2.91.0}/tests/test_oracle_subproject_awareness.py +0 -0
  391. {code_context_control-2.89.1 → code_context_control-2.91.0}/tests/test_oracle_ui_bundle.py +0 -0
  392. {code_context_control-2.89.1 → code_context_control-2.91.0}/tests/test_output_filter.py +0 -0
  393. {code_context_control-2.89.1 → code_context_control-2.91.0}/tests/test_override_grants.py +0 -0
  394. {code_context_control-2.89.1 → code_context_control-2.91.0}/tests/test_override_grants_mcp.py +0 -0
  395. {code_context_control-2.89.1 → code_context_control-2.91.0}/tests/test_override_requests.py +0 -0
  396. {code_context_control-2.89.1 → code_context_control-2.91.0}/tests/test_override_wake.py +0 -0
  397. {code_context_control-2.89.1 → code_context_control-2.91.0}/tests/test_permissions.py +0 -0
  398. {code_context_control-2.89.1 → code_context_control-2.91.0}/tests/test_pm_api.py +0 -0
  399. {code_context_control-2.89.1 → code_context_control-2.91.0}/tests/test_project_manager.py +0 -0
  400. {code_context_control-2.89.1 → code_context_control-2.91.0}/tests/test_project_manager_merge.py +0 -0
  401. {code_context_control-2.89.1 → code_context_control-2.91.0}/tests/test_project_tool.py +0 -0
  402. {code_context_control-2.89.1 → code_context_control-2.91.0}/tests/test_read_coercion.py +0 -0
  403. {code_context_control-2.89.1 → code_context_control-2.91.0}/tests/test_read_edit_parity.py +0 -0
  404. {code_context_control-2.89.1 → code_context_control-2.91.0}/tests/test_related_facts.py +0 -0
  405. {code_context_control-2.89.1 → code_context_control-2.91.0}/tests/test_repo_map.py +0 -0
  406. {code_context_control-2.89.1 → code_context_control-2.91.0}/tests/test_response_boilerplate.py +0 -0
  407. {code_context_control-2.89.1 → code_context_control-2.91.0}/tests/test_retention.py +0 -0
  408. {code_context_control-2.89.1 → code_context_control-2.91.0}/tests/test_review_digest.py +0 -0
  409. {code_context_control-2.89.1 → code_context_control-2.91.0}/tests/test_service_durability.py +0 -0
  410. {code_context_control-2.89.1 → code_context_control-2.91.0}/tests/test_session_benchmark.py +0 -0
  411. {code_context_control-2.89.1 → code_context_control-2.91.0}/tests/test_session_budget.py +0 -0
  412. {code_context_control-2.89.1 → code_context_control-2.91.0}/tests/test_shell_creds.py +0 -0
  413. {code_context_control-2.89.1 → code_context_control-2.91.0}/tests/test_shell_robustness.py +0 -0
  414. {code_context_control-2.89.1 → code_context_control-2.91.0}/tests/test_subproject_exclusion.py +0 -0
  415. {code_context_control-2.89.1 → code_context_control-2.91.0}/tests/test_subproject_federation.py +0 -0
  416. {code_context_control-2.89.1 → code_context_control-2.91.0}/tests/test_subprojects.py +0 -0
  417. {code_context_control-2.89.1 → code_context_control-2.91.0}/tests/test_swe_bench.py +0 -0
  418. {code_context_control-2.89.1 → code_context_control-2.91.0}/tests/test_task_store.py +0 -0
  419. {code_context_control-2.89.1 → code_context_control-2.91.0}/tests/test_task_tool.py +0 -0
  420. {code_context_control-2.89.1 → code_context_control-2.91.0}/tests/test_time_tracker.py +0 -0
  421. {code_context_control-2.89.1 → code_context_control-2.91.0}/tests/test_token_telemetry.py +0 -0
  422. {code_context_control-2.89.1 → code_context_control-2.91.0}/tests/test_tool_registry.py +0 -0
  423. {code_context_control-2.89.1 → code_context_control-2.91.0}/tests/test_upgrade_and_version.py +0 -0
  424. {code_context_control-2.89.1 → code_context_control-2.91.0}/tests/test_validate.py +0 -0
  425. {code_context_control-2.89.1 → code_context_control-2.91.0}/tests/test_vault_write_guard.py +0 -0
  426. {code_context_control-2.89.1 → code_context_control-2.91.0}/tests/test_version_sync.py +0 -0
  427. {code_context_control-2.89.1 → code_context_control-2.91.0}/tests/test_web_security.py +0 -0
  428. {code_context_control-2.89.1 → code_context_control-2.91.0}/tests/test_windows_reliability.py +0 -0
  429. {code_context_control-2.89.1 → code_context_control-2.91.0}/tui/__init__.py +0 -0
  430. {code_context_control-2.89.1 → code_context_control-2.91.0}/tui/backend.py +0 -0
  431. {code_context_control-2.89.1 → code_context_control-2.91.0}/tui/main.py +0 -0
  432. {code_context_control-2.89.1 → code_context_control-2.91.0}/tui/screens/__init__.py +0 -0
  433. {code_context_control-2.89.1 → code_context_control-2.91.0}/tui/screens/benchmark_view.py +0 -0
  434. {code_context_control-2.89.1 → code_context_control-2.91.0}/tui/screens/claudemd_view.py +0 -0
  435. {code_context_control-2.89.1 → code_context_control-2.91.0}/tui/screens/compress_view.py +0 -0
  436. {code_context_control-2.89.1 → code_context_control-2.91.0}/tui/screens/index_view.py +0 -0
  437. {code_context_control-2.89.1 → code_context_control-2.91.0}/tui/screens/init_view.py +0 -0
  438. {code_context_control-2.89.1 → code_context_control-2.91.0}/tui/screens/mcp_view.py +0 -0
  439. {code_context_control-2.89.1 → code_context_control-2.91.0}/tui/screens/optimize_view.py +0 -0
  440. {code_context_control-2.89.1 → code_context_control-2.91.0}/tui/screens/pipe_view.py +0 -0
  441. {code_context_control-2.89.1 → code_context_control-2.91.0}/tui/screens/projects_view.py +0 -0
  442. {code_context_control-2.89.1 → code_context_control-2.91.0}/tui/screens/search_view.py +0 -0
  443. {code_context_control-2.89.1 → code_context_control-2.91.0}/tui/screens/session_view.py +0 -0
  444. {code_context_control-2.89.1 → code_context_control-2.91.0}/tui/screens/stats.py +0 -0
  445. {code_context_control-2.89.1 → code_context_control-2.91.0}/tui/screens/ui_view.py +0 -0
  446. {code_context_control-2.89.1 → code_context_control-2.91.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.91.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.91.0"
96
96
 
97
97
 
98
98
  def _compress_file_cli(compressor, path, mode="smart", **kw):
@@ -7426,10 +7426,39 @@ def _oracle_open(args):
7426
7426
  webbrowser.open(url)
7427
7427
 
7428
7428
 
7429
+ def _oracle_service_cmd(args):
7430
+ """`c3 oracle serve --install | --uninstall | --status` — mirrors `c3 hub`."""
7431
+ from services.oracle_service import OracleService
7432
+ svc = OracleService()
7433
+ port = getattr(args, "port", None) or svc.default_port()
7434
+
7435
+ if getattr(args, "install", False):
7436
+ res = svc.install(port)
7437
+ print(res.get("output", "Service installed."))
7438
+ if res.get("success"):
7439
+ print(f"Oracle will start at login (no terminal window); log: {svc.LOG_FILE}")
7440
+ return
7441
+ if getattr(args, "uninstall", False):
7442
+ res = svc.uninstall()
7443
+ print(res.get("output", "Service uninstalled."))
7444
+ return
7445
+ res = svc.status()
7446
+ print(f"Oracle Service Status ({res.get('platform', 'unknown')}):")
7447
+ print(f" Installed: {res.get('installed')}")
7448
+ print(f" Running : {res.get('running')}")
7449
+ print(f" Port : {res.get('port')} (bind {res.get('bind_host')}, MCP {res.get('mcp_port')})")
7450
+ print(f" URL : {res.get('url')}")
7451
+ print(f" Method : {res.get('method')}")
7452
+ print(f" Log : {res.get('log_path')}")
7453
+
7454
+
7429
7455
  def cmd_oracle(args):
7430
7456
  """Oracle dashboard server + Discovery API key management."""
7431
7457
  sub = getattr(args, "oracle_cmd", None)
7432
7458
  if sub in ("serve", "start"):
7459
+ if any(getattr(args, f, False) for f in ("install", "uninstall", "status")):
7460
+ _oracle_service_cmd(args)
7461
+ return
7433
7462
  # Lazy import: run_oracle builds all Oracle services (matches
7434
7463
  # cmd_hub's deferred-import style so bare `c3` stays fast).
7435
7464
  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</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.</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>
@@ -3407,6 +3407,63 @@ def api_hub_restart():
3407
3407
  return jsonify({"restarting": True})
3408
3408
 
3409
3409
 
3410
+ # ─── Routes: oracle service (background daemon for `c3 oracle serve`) ───────
3411
+ #
3412
+ # Same shape as the hub's own service routes above. Port and bind host come
3413
+ # from ~/.c3/oracle/config.json, not from the hub config. A successful
3414
+ # install/start fills an EMPTY hub `oracle_url` with the Oracle's address so
3415
+ # the top bar's Open Oracle link appears without a second trip to settings.
3416
+
3417
+ def _oracle_service():
3418
+ from services.oracle_service import OracleService
3419
+ return OracleService()
3420
+
3421
+
3422
+ def _adopt_oracle_url(svc, result: dict) -> dict:
3423
+ result = dict(result or {})
3424
+ if not result.get("success"):
3425
+ return result
3426
+ cfg = _read_hub_config()
3427
+ if not (cfg.get("oracle_url") or "").strip():
3428
+ cfg["oracle_url"] = svc.url()
3429
+ _write_hub_config(cfg)
3430
+ result["oracle_url_set"] = True
3431
+ result["oracle_url"] = cfg["oracle_url"]
3432
+ return result
3433
+
3434
+
3435
+ @app.route("/api/oracle/service", methods=["GET"])
3436
+ def api_oracle_service_status():
3437
+ """Whether the Oracle is registered as a startup service / currently up."""
3438
+ return jsonify(_oracle_service().status())
3439
+
3440
+
3441
+ @app.route("/api/oracle/service/install", methods=["POST"])
3442
+ def api_oracle_service_install():
3443
+ """Register the Oracle to start at login (windowless) and start it now."""
3444
+ svc = _oracle_service()
3445
+ return jsonify(_adopt_oracle_url(svc, svc.install()))
3446
+
3447
+
3448
+ @app.route("/api/oracle/service/uninstall", methods=["POST"])
3449
+ def api_oracle_service_uninstall():
3450
+ """Remove the Oracle's startup registration (does not stop a running one)."""
3451
+ return jsonify(_oracle_service().uninstall())
3452
+
3453
+
3454
+ @app.route("/api/oracle/service/start", methods=["POST"])
3455
+ def api_oracle_service_start():
3456
+ """Start the Oracle as a detached background process (no terminal)."""
3457
+ svc = _oracle_service()
3458
+ return jsonify(_adopt_oracle_url(svc, svc.start()))
3459
+
3460
+
3461
+ @app.route("/api/oracle/service/stop", methods=["POST"])
3462
+ def api_oracle_service_stop():
3463
+ """Kill the Oracle process listening on its configured port."""
3464
+ return jsonify(_oracle_service().stop())
3465
+
3466
+
3410
3467
  # ─── Routes: sessions ────────────────────────────────────────────────────────
3411
3468
 
3412
3469
  @app.route("/api/sessions/start", methods=["POST"])
@@ -142,7 +142,8 @@ function App() {
142
142
  onOpenProject={(p, tab) => { setSearchOpen(false); openDrill(p, tab || 'overview'); }} />
143
143
  {modal &&
144
144
  <HubModals modal={modal} projects={projects}
145
- onClose={() => setModal(null)} onChanged={loadProjects} />}
145
+ onClose={() => setModal(null)}
146
+ onChanged={() => { loadConfig(); loadProjects(); }} />}
146
147
  <ToastHost />
147
148
  </div>
148
149
  );
@@ -15,10 +15,14 @@ const HUB_CREDS_EMPTY_FORM = {
15
15
  fields: {},
16
16
  };
17
17
 
18
- // Structured kinds (v2.87.0): per-type field sets composed into a JSON
19
- // object client-side. `hidden` fields render as password inputs. These
20
- // entries are inject-only — the server refuses agent_readable/inject and
18
+ // Structured kinds (v2.87.0; `login` v2.90.0): per-type field sets composed
19
+ // into a JSON object client-side. `hidden` fields render as password inputs.
20
+ // These entries are inject-only — the server refuses agent_readable/inject and
21
21
  // there is no reveal path anywhere.
22
+ // This table MUST mirror services/credential_store._SCHEMAS — a kind the store
23
+ // accepts and this table omits is unreachable from the browser and, worse,
24
+ // renders as a plain secret with exposure toggles the server will refuse.
25
+ // tests/test_credential_ui_parity.py asserts the two stay in step.
22
26
  const CREDS_STRUCTURED = {
23
27
  card: { required: ['cardholder', 'number', 'expiry'],
24
28
  optional: ['cvc', 'billing_zip'], hidden: ['number', 'cvc'] },
@@ -26,11 +30,20 @@ const CREDS_STRUCTURED = {
26
30
  optional: ['recipient', 'street2', 'country', 'phone'], hidden: [] },
27
31
  identity: { required: ['full_name'],
28
32
  optional: ['dob', 'ssn', 'phone', 'email'], hidden: ['ssn', 'dob'] },
33
+ login: { required: ['site_id', 'canonical_origin', 'username', 'password'],
34
+ optional: ['totp_secret'], hidden: ['password', 'totp_secret'] },
29
35
  };
30
36
 
31
37
  const credsDisplayText = (entry) => {
32
38
  const d = entry.display || {};
33
39
  if (entry.type === 'card') return `${d.brand || 'card'} ••••${d.last4 || '????'}`;
40
+ // login's projection carries has_totp as a BOOLEAN — the generic join below
41
+ // would render it as the word "true". Username is absent by design.
42
+ if (entry.type === 'login') {
43
+ const bits = [d.site_id, d.origin].filter(Boolean);
44
+ if (d.has_totp) bits.push('2FA');
45
+ return bits.join(' · ');
46
+ }
34
47
  const vals = Object.values(d).filter(Boolean);
35
48
  return vals.length ? vals.join(', ') : '';
36
49
  };
@@ -1168,6 +1181,7 @@ function CredsManager({ path, projectName, onChanged }) {
1168
1181
  <option value="card">card — credit/debit card (inject-only)</option>
1169
1182
  <option value="address">address — postal address (inject-only)</option>
1170
1183
  <option value="identity">identity — personal info (inject-only)</option>
1184
+ <option value="login">login — website login (inject-only, storage only)</option>
1171
1185
  </select>
1172
1186
  </div>
1173
1187
  <div>
@@ -1192,6 +1206,15 @@ function CredsManager({ path, projectName, onChanged }) {
1192
1206
  (<span className="mono">{'{{cred:NAME.field}}'}</span> /{' '}
1193
1207
  <span className="mono">env_creds='NAME.field'</span>) but can never
1194
1208
  reveal them, and they never auto-inject.
1209
+ {form.type === 'login' && (
1210
+ <div style={{ marginTop: 4 }}>
1211
+ Storage only — C3 has no browser and does not log in to anything.{' '}
1212
+ <span className="mono">canonical_origin</span> is https-only and
1213
+ stored normalized so a separate out-of-process runner can pin this
1214
+ credential to exactly one origin before typing it.{' '}
1215
+ <span className="mono">totp_secret</span> is base32.
1216
+ </div>
1217
+ )}
1195
1218
  </div>
1196
1219
  ) : (
1197
1220
  <div style={{ display: 'flex', gap: 18, marginTop: 10, fontSize: 12, color: T.text }}>
@@ -1,9 +1,14 @@
1
1
  // ─── Hub settings modal ─────────────────────────────────────────
2
2
  // Config: GET/POST /api/hub/config {port, auto_open_browser, oracle_url,
3
- // runtime_cache_size}. Service: GET /api/hub/service + POST
3
+ // runtime_cache_size}. Hub service: GET /api/hub/service + POST
4
4
  // /api/hub/service/install|uninstall|start|stop. Restart: POST /api/hub/restart.
5
+ // Oracle service: GET /api/oracle/service + POST
6
+ // /api/oracle/service/install|uninstall|start|stop — runs `c3 oracle serve`
7
+ // windowless in the background; install also registers it to start at login.
5
8
  // Theme is handled by the topbar; bind host is CLI/config-file only (read-only here).
6
9
 
10
+ let _oraclePollTimer = null;
11
+
7
12
  function SettingsModal({ onClose, onChanged }) {
8
13
  const [cfg, setCfg] = useState(null);
9
14
  const [port, setPort] = useState('');
@@ -11,14 +16,32 @@ function SettingsModal({ onClose, onChanged }) {
11
16
  const [oracleUrl, setOracleUrl] = useState('');
12
17
  const [cacheSize, setCacheSize] = useState(8);
13
18
  const [saving, setSaving] = useState(false);
14
- const [svc, setSvc] = useState(null); // {installed, running, method, port, log_path} | {error}
19
+ const [svc, setSvc] = useState(null); // hub: {installed, running, method, port, log_path} | {error}
15
20
  const [svcBusy, setSvcBusy] = useState('');
16
- const [confirmAction, setConfirmAction] = useState(null); // 'stop' | 'uninstall'
21
+ const [osvc, setOsvc] = useState(null); // oracle: same shape + {url, bind_host, mcp_port}
22
+ const [osvcBusy, setOsvcBusy] = useState('');
23
+ const [confirmAction, setConfirmAction] = useState(null); // 'stop' | 'uninstall' | 'oracle-stop' | 'oracle-uninstall'
17
24
 
18
25
  const loadSvc = async () => {
19
26
  try { setSvc(await api.get('/api/hub/service')); }
20
27
  catch { setSvc({ error: true }); }
21
28
  };
29
+ const loadOsvc = async () => {
30
+ try { setOsvc(await api.get('/api/oracle/service')); }
31
+ catch { setOsvc({ error: true }); }
32
+ };
33
+
34
+ // After a start the Oracle needs a few seconds before /api/health answers —
35
+ // poll until it reports running, give up after ~30 s.
36
+ const pollOsvc = (attempt = 0) => {
37
+ clearTimeout(_oraclePollTimer);
38
+ _oraclePollTimer = setTimeout(async () => {
39
+ let d = null;
40
+ try { d = await api.get('/api/oracle/service'); setOsvc(d); }
41
+ catch { setOsvc({ error: true }); }
42
+ if (d && !d.running && attempt < 12) pollOsvc(attempt + 1);
43
+ }, attempt === 0 ? 1500 : 2500);
44
+ };
22
45
 
23
46
  useEffect(() => {
24
47
  (async () => {
@@ -33,7 +56,9 @@ function SettingsModal({ onClose, onChanged }) {
33
56
  notify('Could not load hub config', 'err');
34
57
  }
35
58
  loadSvc();
59
+ loadOsvc();
36
60
  })();
61
+ return () => clearTimeout(_oraclePollTimer);
37
62
  }, []);
38
63
 
39
64
  const save = async () => {
@@ -81,6 +106,27 @@ function SettingsModal({ onClose, onChanged }) {
81
106
  setTimeout(loadSvc, 800);
82
107
  };
83
108
 
109
+ const osvcAction = async (action) => {
110
+ setConfirmAction(null);
111
+ setOsvcBusy(action);
112
+ try {
113
+ const d = await api.post(`/api/oracle/service/${action}`, {});
114
+ const ok = d.success !== false;
115
+ notify(d.output || `Oracle ${action} ${ok ? 'succeeded' : 'failed'}`, ok ? 'ok' : 'err');
116
+ if (ok && d.oracle_url_set) {
117
+ // The hub had no oracle_url; the server filled it so the top-bar link appears.
118
+ setOracleUrl(d.oracle_url || '');
119
+ notify(`Oracle URL set to ${d.oracle_url} — the Open Oracle button is now in the top bar`);
120
+ if (onChanged) onChanged();
121
+ }
122
+ if (ok && (action === 'start' || action === 'install')) pollOsvc();
123
+ } catch (e) {
124
+ notify(`Oracle ${action} failed: ${e.message}`, 'err');
125
+ }
126
+ setOsvcBusy('');
127
+ setTimeout(loadOsvc, 800);
128
+ };
129
+
84
130
  const restartHub = async () => {
85
131
  try { await api.post('/api/hub/restart', {}); } catch { /* server drops mid-response */ }
86
132
  notify('Hub restarting…', 'warn');
@@ -109,16 +155,56 @@ function SettingsModal({ onClose, onChanged }) {
109
155
  fontSize: 13, outline: 'none', fontFamily: 'inherit',
110
156
  });
111
157
 
158
+ // Shared status line for both service blocks.
159
+ const svcSummary = (s) => {
160
+ let label, color;
161
+ if (!s) { label = 'checking…'; color = T.textMuted; }
162
+ else if (s.error) { label = 'unavailable'; color = T.error; }
163
+ else if (!s.installed) {
164
+ label = s.running === true ? 'running (not installed)' : 'not installed';
165
+ color = s.running === true ? T.accent : T.textMuted;
166
+ } else {
167
+ label = s.running === true ? 'running' : s.running === false ? 'stopped' : 'installed';
168
+ color = s.running !== false ? T.accent : T.textMuted;
169
+ }
170
+ return { label, color };
171
+ };
172
+
173
+ const serviceStatus = (s) => {
174
+ const { label, color } = svcSummary(s);
175
+ return (
176
+ <div>
177
+ <div style={{ display: 'flex', alignItems: 'center', gap: 8, marginBottom: 8 }}>
178
+ <GlowDot color={color} />
179
+ <span className="mono" style={{ fontSize: 12, color }}>{label}</span>
180
+ {s && !s.error && s.method && (
181
+ <span className="mono" style={{ fontSize: 11, color: T.textDim }}>
182
+ {s.method}{s.port ? ` (port ${s.port})` : ''}
183
+ </span>
184
+ )}
185
+ </div>
186
+ {s && !s.error && s.log_path && (
187
+ <div className="mono" style={{ fontSize: 11, color: T.textDim, marginBottom: 8, wordBreak: 'break-all' }}>
188
+ log: {s.log_path}
189
+ </div>
190
+ )}
191
+ </div>
192
+ );
193
+ };
194
+
195
+ const busyLine = (what) => (
196
+ <div style={{ fontSize: 11, color: T.textMuted, marginTop: 8, animation: 'pulse 1s infinite' }}>
197
+ {what}…
198
+ </div>
199
+ );
200
+
112
201
  const svcInstalled = svc && !svc.error && svc.installed;
113
- const svcLabel = !svc ? 'checking…'
114
- : svc.error ? 'unavailable'
115
- : !svc.installed ? 'not installed'
116
- : svc.running === true ? 'running'
117
- : svc.running === false ? 'stopped'
118
- : 'installed';
119
- const svcColor = !svc ? T.textMuted
120
- : svc.error ? T.error
121
- : (svc.installed && svc.running !== false) ? T.accent : T.textMuted;
202
+ const osvcInstalled = osvc && !osvc.error && osvc.installed;
203
+ const osvcRunning = osvc && !osvc.error && osvc.running === true;
204
+ const openOracle = () => {
205
+ const url = oracleUrl.trim() || (osvc && osvc.url) || '';
206
+ if (url) window.open(url, '_blank', 'noopener');
207
+ };
122
208
 
123
209
  return (
124
210
  <Modal title="Hub Settings" width={520} onClose={onClose}>
@@ -138,27 +224,14 @@ function SettingsModal({ onClose, onChanged }) {
138
224
  ), 'Max project runtimes kept warm for drill-in and global search.')}
139
225
  {fieldRow('Oracle URL', (
140
226
  <input value={oracleUrl} onChange={e => setOracleUrl(e.target.value)}
141
- placeholder="http://localhost:3333" className="mono" style={inputStyle(220)} />
142
- ), 'Optional — link to a running C3 Oracle instance.')}
227
+ placeholder="http://localhost:3331" className="mono" style={inputStyle(220)} />
228
+ ), 'Optional — link to a running C3 Oracle instance. Filled in automatically when you start the Oracle below.')}
143
229
  <div style={{ display: 'flex', justifyContent: 'flex-end', marginTop: 10 }}>
144
230
  <Btn onClick={save} disabled={saving || !cfg}>{saving ? 'Saving…' : 'Save settings'}</Btn>
145
231
  </div>
146
232
 
147
233
  {sectionLabel('Startup service')}
148
- <div style={{ display: 'flex', alignItems: 'center', gap: 8, marginBottom: 8 }}>
149
- <GlowDot color={svcColor} />
150
- <span className="mono" style={{ fontSize: 12, color: svcColor }}>{svcLabel}</span>
151
- {svc && !svc.error && svc.method && (
152
- <span className="mono" style={{ fontSize: 11, color: T.textDim }}>
153
- {svc.method}{svc.port ? ` (port ${svc.port})` : ''}
154
- </span>
155
- )}
156
- </div>
157
- {svc && !svc.error && svc.log_path && (
158
- <div className="mono" style={{ fontSize: 11, color: T.textDim, marginBottom: 8, wordBreak: 'break-all' }}>
159
- log: {svc.log_path}
160
- </div>
161
- )}
234
+ {serviceStatus(svc)}
162
235
  <div style={{ display: 'flex', flexWrap: 'wrap', gap: 8 }}>
163
236
  <Btn variant="ghost" onClick={() => svcAction('install')} disabled={!!svcBusy}>
164
237
  {svcInstalled ? 'Reinstall' : 'Install'}
@@ -174,11 +247,7 @@ function SettingsModal({ onClose, onChanged }) {
174
247
  <I name="refresh" size={12} color={T.textMuted} />Restart hub
175
248
  </Btn>
176
249
  </div>
177
- {svcBusy && (
178
- <div style={{ fontSize: 11, color: T.textMuted, marginTop: 8, animation: 'pulse 1s infinite' }}>
179
- {svcBusy}…
180
- </div>
181
- )}
250
+ {svcBusy && busyLine(svcBusy)}
182
251
  {cfg && (
183
252
  <div style={{ fontSize: 11, color: T.textDim, marginTop: 10 }}>
184
253
  {cfg.has_terminal
@@ -187,6 +256,40 @@ function SettingsModal({ onClose, onChanged }) {
187
256
  </div>
188
257
  )}
189
258
 
259
+ {sectionLabel('Oracle service')}
260
+ {serviceStatus(osvc)}
261
+ {osvc && !osvc.error && (
262
+ <div className="mono" style={{ fontSize: 11, color: T.textDim, marginBottom: 8, wordBreak: 'break-all' }}>
263
+ bind {osvc.bind_host || '127.0.0.1'} · MCP port {osvc.mcp_port || 3332} · {osvc.url}
264
+ </div>
265
+ )}
266
+ <div style={{ display: 'flex', flexWrap: 'wrap', gap: 8 }}>
267
+ <Btn variant="ghost" onClick={() => osvcAction('install')} disabled={!!osvcBusy}>
268
+ {osvcInstalled ? 'Reinstall' : 'Install'}
269
+ </Btn>
270
+ {osvcInstalled && (
271
+ <Btn variant="ghost" onClick={() => setConfirmAction('oracle-uninstall')} disabled={!!osvcBusy}>Uninstall</Btn>
272
+ )}
273
+ {!osvcRunning && (
274
+ <Btn variant="ghost" onClick={() => osvcAction('start')} disabled={!!osvcBusy || !osvc}>
275
+ <I name="play" size={12} color={T.textMuted} />Start oracle
276
+ </Btn>
277
+ )}
278
+ {osvcRunning && (
279
+ <Btn variant="ghost" color={T.error} onClick={() => setConfirmAction('oracle-stop')} disabled={!!osvcBusy}>Stop oracle</Btn>
280
+ )}
281
+ {osvcRunning && (
282
+ <Btn variant="ghost" onClick={openOracle}>
283
+ <I name="external" size={12} color={T.textMuted} />Open
284
+ </Btn>
285
+ )}
286
+ </div>
287
+ {osvcBusy && busyLine(`oracle ${osvcBusy}`)}
288
+ <div style={{ fontSize: 11, color: T.textDim, marginTop: 10 }}>
289
+ Runs <span className="mono">c3 oracle serve</span> in the background — no terminal window.
290
+ Install also registers it to start at login, so it survives reboots.
291
+ </div>
292
+
190
293
  {confirmAction === 'stop' && (
191
294
  <ConfirmDialog title="Stop Hub"
192
295
  message="The page will become unreachable until the hub is restarted (c3 hub)."
@@ -199,6 +302,18 @@ function SettingsModal({ onClose, onChanged }) {
199
302
  confirmLabel="Uninstall" danger
200
303
  onConfirm={() => svcAction('uninstall')} onCancel={() => setConfirmAction(null)} />
201
304
  )}
305
+ {confirmAction === 'oracle-stop' && (
306
+ <ConfirmDialog title="Stop Oracle"
307
+ message="Kills the Oracle process (dashboard, discovery API and MCP endpoint). It will start again at the next login if installed, or via Start oracle."
308
+ confirmLabel="Stop" danger
309
+ onConfirm={() => osvcAction('stop')} onCancel={() => setConfirmAction(null)} />
310
+ )}
311
+ {confirmAction === 'oracle-uninstall' && (
312
+ <ConfirmDialog title="Uninstall Oracle Service"
313
+ message="The Oracle will no longer auto-start on login. A running Oracle keeps running."
314
+ confirmLabel="Uninstall" danger
315
+ onConfirm={() => osvcAction('uninstall')} onCancel={() => setConfirmAction(null)} />
316
+ )}
202
317
  </Modal>
203
318
  );
204
319
  }
@@ -1039,15 +1039,19 @@ async def c3_credentials(
1039
1039
  often it was used: counts by surface, recent events for THIS project, other
1040
1040
  projects reduced to counts), reveal (name — only entries the user marked
1041
1041
  agent_readable), set (name, value [scope=project|global]
1042
- [ctype=token|env|multiline|address|identity|card] [description] [env_var] [inject]),
1043
- delete (name [scope]).
1042
+ [ctype=token|env|multiline|address|identity|card|login] [description] [env_var]
1043
+ [inject]), delete (name [scope]).
1044
1044
  To USE a credential, do NOT reveal it — pass env_creds='NAME1,NAME2' to c3_shell
1045
1045
  (injected as env vars) or write {{cred:NAME}} inside the cmd (expanded server-side);
1046
1046
  the decoded value never enters model context.
1047
- STRUCTURED kinds (address/identity/card) hold named fields: set takes value as a
1048
- JSON object (card: cardholder/number/expiry[/cvc/billing_zip]; address:
1047
+ STRUCTURED kinds (address/identity/card/login) hold named fields: set takes value
1048
+ as a JSON object (card: cardholder/number/expiry[/cvc/billing_zip]; address:
1049
1049
  street1/city/state/zip[/recipient/street2/country/phone]; identity:
1050
- full_name[/dob/ssn/phone/email]). Address a FIELD at the boundary —
1050
+ full_name[/dob/ssn/phone/email]; login: site_id/canonical_origin/username/password
1051
+ [/totp_secret]). `login` is STORAGE ONLY — C3 has no browser and never types a
1052
+ password anywhere. canonical_origin is https-only and stored normalized so an
1053
+ external runner can bind the credential to one origin; do NOT build a browser
1054
+ login runner in this package. Address a FIELD at the boundary —
1051
1055
  env_creds='CARD.number' (env $CARD_NUMBER) or {{cred:CARD.number}} in cmd. Reveal
1052
1056
  is permanently disabled for them and they never auto-inject; have the user enter
1053
1057
  the values via the Credentials UI or `c3 creds set` so they never enter the chat.
@@ -9,9 +9,17 @@ credential is c3_shell: ``env_creds='NAME1,NAME2'`` (env injection) or
9
9
  ``{{cred:NAME}}`` in the command (server-side expansion) — the decoded value
10
10
  never enters model context.
11
11
 
12
- Structured kinds (address/identity/card) go further: reveal is permanently
12
+ Structured kinds (address/identity/card/login) go further: reveal is permanently
13
13
  disabled regardless of flags, and only individual FIELDS are addressable —
14
14
  ``env_creds='CARD.number'`` or ``{{cred:CARD.number}}``.
15
+
16
+ ``login`` is storage only. C3 has no browser surface and must not grow one:
17
+ a login runner in which the AGENT chooses the destination URL turns page-content
18
+ prompt injection into credential exfiltration, and a guard written into a script
19
+ that already holds the plaintext is not a boundary. The ``canonical_origin``
20
+ field is stored (https-only, normalized) so that a separate, out-of-process
21
+ runner can pin the credential to one origin and validate the live top-level
22
+ frame before typing. That runner is deliberately somebody else's package.
15
23
  """
16
24
  from __future__ import annotations
17
25