code-context-control 2.143.0__tar.gz → 2.145.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 (570) hide show
  1. {code_context_control-2.143.0 → code_context_control-2.145.0}/PKG-INFO +2 -1
  2. {code_context_control-2.143.0 → code_context_control-2.145.0}/cli/c3.py +131 -12
  3. {code_context_control-2.143.0 → code_context_control-2.145.0}/cli/commands/parser.py +21 -6
  4. {code_context_control-2.143.0 → code_context_control-2.145.0}/cli/hook_pretool_enforce.py +1 -0
  5. {code_context_control-2.143.0 → code_context_control-2.145.0}/cli/hub_server.py +32 -24
  6. {code_context_control-2.143.0 → code_context_control-2.145.0}/cli/hub_ui/components/hub_credentials.js +32 -0
  7. {code_context_control-2.143.0 → code_context_control-2.145.0}/cli/server.py +7 -21
  8. {code_context_control-2.143.0 → code_context_control-2.145.0}/cli/tools/credentials.py +25 -8
  9. {code_context_control-2.143.0 → code_context_control-2.145.0}/cli/ui/components/credentials.js +1 -0
  10. {code_context_control-2.143.0 → code_context_control-2.145.0}/code_context_control.egg-info/PKG-INFO +2 -1
  11. {code_context_control-2.143.0 → code_context_control-2.145.0}/code_context_control.egg-info/SOURCES.txt +2 -0
  12. {code_context_control-2.143.0 → code_context_control-2.145.0}/code_context_control.egg-info/requires.txt +1 -0
  13. {code_context_control-2.143.0 → code_context_control-2.145.0}/oracle/services/mobile_api.py +7 -15
  14. {code_context_control-2.143.0 → code_context_control-2.145.0}/pyproject.toml +2 -1
  15. {code_context_control-2.143.0 → code_context_control-2.145.0}/services/access_guard.py +2 -1
  16. code_context_control-2.145.0/services/credential_backup.py +333 -0
  17. {code_context_control-2.143.0 → code_context_control-2.145.0}/services/credential_store.py +92 -25
  18. {code_context_control-2.143.0 → code_context_control-2.145.0}/services/override_policy.py +3 -1
  19. code_context_control-2.145.0/tests/test_credential_backup.py +245 -0
  20. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_credential_store.py +33 -0
  21. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_credentials_routes.py +19 -1
  22. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_credentials_tool.py +16 -0
  23. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_creds_cli_smoke.py +20 -0
  24. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_hub_credentials_routes_write.py +14 -0
  25. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_mobile_security_api.py +12 -0
  26. {code_context_control-2.143.0 → code_context_control-2.145.0}/LICENSE +0 -0
  27. {code_context_control-2.143.0 → code_context_control-2.145.0}/README.md +0 -0
  28. {code_context_control-2.143.0 → code_context_control-2.145.0}/cli/__init__.py +0 -0
  29. {code_context_control-2.143.0 → code_context_control-2.145.0}/cli/_hook_utils.py +0 -0
  30. {code_context_control-2.143.0 → code_context_control-2.145.0}/cli/_shell_writes.py +0 -0
  31. {code_context_control-2.143.0 → code_context_control-2.145.0}/cli/commands/__init__.py +0 -0
  32. {code_context_control-2.143.0 → code_context_control-2.145.0}/cli/commands/common.py +0 -0
  33. {code_context_control-2.143.0 → code_context_control-2.145.0}/cli/docs.html +0 -0
  34. {code_context_control-2.143.0 → code_context_control-2.145.0}/cli/edits.html +0 -0
  35. {code_context_control-2.143.0 → code_context_control-2.145.0}/cli/guide/access.html +0 -0
  36. {code_context_control-2.143.0 → code_context_control-2.145.0}/cli/guide/bitbucket.html +0 -0
  37. {code_context_control-2.143.0 → code_context_control-2.145.0}/cli/guide/credentials.html +0 -0
  38. {code_context_control-2.143.0 → code_context_control-2.145.0}/cli/guide/getting-started.html +0 -0
  39. {code_context_control-2.143.0 → code_context_control-2.145.0}/cli/guide/index.html +0 -0
  40. {code_context_control-2.143.0 → code_context_control-2.145.0}/cli/guide/masking.html +0 -0
  41. {code_context_control-2.143.0 → code_context_control-2.145.0}/cli/guide/oracle.html +0 -0
  42. {code_context_control-2.143.0 → code_context_control-2.145.0}/cli/guide/shared.css +0 -0
  43. {code_context_control-2.143.0 → code_context_control-2.145.0}/cli/guide/tools.html +0 -0
  44. {code_context_control-2.143.0 → code_context_control-2.145.0}/cli/guide/workflow.html +0 -0
  45. {code_context_control-2.143.0 → code_context_control-2.145.0}/cli/hook_access_guard.py +0 -0
  46. {code_context_control-2.143.0 → code_context_control-2.145.0}/cli/hook_agent_model.py +0 -0
  47. {code_context_control-2.143.0 → code_context_control-2.145.0}/cli/hook_artifact.py +0 -0
  48. {code_context_control-2.143.0 → code_context_control-2.145.0}/cli/hook_auto_snapshot.py +0 -0
  49. {code_context_control-2.143.0 → code_context_control-2.145.0}/cli/hook_c3_signal.py +0 -0
  50. {code_context_control-2.143.0 → code_context_control-2.145.0}/cli/hook_c3read.py +0 -0
  51. {code_context_control-2.143.0 → code_context_control-2.145.0}/cli/hook_codex_lifecycle.py +0 -0
  52. {code_context_control-2.143.0 → code_context_control-2.145.0}/cli/hook_dispatch.py +0 -0
  53. {code_context_control-2.143.0 → code_context_control-2.145.0}/cli/hook_edit_ledger.py +0 -0
  54. {code_context_control-2.143.0 → code_context_control-2.145.0}/cli/hook_edit_unlock.py +0 -0
  55. {code_context_control-2.143.0 → code_context_control-2.145.0}/cli/hook_filter.py +0 -0
  56. {code_context_control-2.143.0 → code_context_control-2.145.0}/cli/hook_ghost_files.py +0 -0
  57. {code_context_control-2.143.0 → code_context_control-2.145.0}/cli/hook_prompt_recall.py +0 -0
  58. {code_context_control-2.143.0 → code_context_control-2.145.0}/cli/hook_read.py +0 -0
  59. {code_context_control-2.143.0 → code_context_control-2.145.0}/cli/hook_session_end.py +0 -0
  60. {code_context_control-2.143.0 → code_context_control-2.145.0}/cli/hook_session_open.py +0 -0
  61. {code_context_control-2.143.0 → code_context_control-2.145.0}/cli/hook_session_stats.py +0 -0
  62. {code_context_control-2.143.0 → code_context_control-2.145.0}/cli/hook_terse_advisor.py +0 -0
  63. {code_context_control-2.143.0 → code_context_control-2.145.0}/cli/hub_ui/app.js +0 -0
  64. {code_context_control-2.143.0 → code_context_control-2.145.0}/cli/hub_ui/components/add_project.js +0 -0
  65. {code_context_control-2.143.0 → code_context_control-2.145.0}/cli/hub_ui/components/config_editor.js +0 -0
  66. {code_context_control-2.143.0 → code_context_control-2.145.0}/cli/hub_ui/components/drill_artifacts.js +0 -0
  67. {code_context_control-2.143.0 → code_context_control-2.145.0}/cli/hub_ui/components/drill_health.js +0 -0
  68. {code_context_control-2.143.0 → code_context_control-2.145.0}/cli/hub_ui/components/drill_panel.js +0 -0
  69. {code_context_control-2.143.0 → code_context_control-2.145.0}/cli/hub_ui/components/drill_subprojects.js +0 -0
  70. {code_context_control-2.143.0 → code_context_control-2.145.0}/cli/hub_ui/components/drill_tasks.js +0 -0
  71. {code_context_control-2.143.0 → code_context_control-2.145.0}/cli/hub_ui/components/drill_views.js +0 -0
  72. {code_context_control-2.143.0 → code_context_control-2.145.0}/cli/hub_ui/components/global_search.js +0 -0
  73. {code_context_control-2.143.0 → code_context_control-2.145.0}/cli/hub_ui/components/hub_access.js +0 -0
  74. {code_context_control-2.143.0 → code_context_control-2.145.0}/cli/hub_ui/components/hub_ci.js +0 -0
  75. {code_context_control-2.143.0 → code_context_control-2.145.0}/cli/hub_ui/components/hub_cred_audit.js +0 -0
  76. {code_context_control-2.143.0 → code_context_control-2.145.0}/cli/hub_ui/components/hub_enforcement.js +0 -0
  77. {code_context_control-2.143.0 → code_context_control-2.145.0}/cli/hub_ui/components/hub_locks.js +0 -0
  78. {code_context_control-2.143.0 → code_context_control-2.145.0}/cli/hub_ui/components/hub_sessions.js +0 -0
  79. {code_context_control-2.143.0 → code_context_control-2.145.0}/cli/hub_ui/components/hub_tokens.js +0 -0
  80. {code_context_control-2.143.0 → code_context_control-2.145.0}/cli/hub_ui/components/mcp_manager.js +0 -0
  81. {code_context_control-2.143.0 → code_context_control-2.145.0}/cli/hub_ui/components/modals.js +0 -0
  82. {code_context_control-2.143.0 → code_context_control-2.145.0}/cli/hub_ui/components/project_card.js +0 -0
  83. {code_context_control-2.143.0 → code_context_control-2.145.0}/cli/hub_ui/components/project_tree.js +0 -0
  84. {code_context_control-2.143.0 → code_context_control-2.145.0}/cli/hub_ui/components/session_drawer.js +0 -0
  85. {code_context_control-2.143.0 → code_context_control-2.145.0}/cli/hub_ui/components/settings_modal.js +0 -0
  86. {code_context_control-2.143.0 → code_context_control-2.145.0}/cli/hub_ui/components/sidebar.js +0 -0
  87. {code_context_control-2.143.0 → code_context_control-2.145.0}/cli/hub_ui/components/summary_bar.js +0 -0
  88. {code_context_control-2.143.0 → code_context_control-2.145.0}/cli/hub_ui/components/task_board.js +0 -0
  89. {code_context_control-2.143.0 → code_context_control-2.145.0}/cli/hub_ui/components/toasts.js +0 -0
  90. {code_context_control-2.143.0 → code_context_control-2.145.0}/cli/hub_ui/components/topbar.js +0 -0
  91. {code_context_control-2.143.0 → code_context_control-2.145.0}/cli/hub_ui/state.js +0 -0
  92. {code_context_control-2.143.0 → code_context_control-2.145.0}/cli/hub_ui.html +0 -0
  93. {code_context_control-2.143.0 → code_context_control-2.145.0}/cli/mcp_proxy.py +0 -0
  94. {code_context_control-2.143.0 → code_context_control-2.145.0}/cli/mcp_server.py +0 -0
  95. {code_context_control-2.143.0 → code_context_control-2.145.0}/cli/progress.py +0 -0
  96. {code_context_control-2.143.0 → code_context_control-2.145.0}/cli/tools/__init__.py +0 -0
  97. {code_context_control-2.143.0 → code_context_control-2.145.0}/cli/tools/_grants.py +0 -0
  98. {code_context_control-2.143.0 → code_context_control-2.145.0}/cli/tools/_helpers.py +0 -0
  99. {code_context_control-2.143.0 → code_context_control-2.145.0}/cli/tools/agent.py +0 -0
  100. {code_context_control-2.143.0 → code_context_control-2.145.0}/cli/tools/artifacts.py +0 -0
  101. {code_context_control-2.143.0 → code_context_control-2.145.0}/cli/tools/bitbucket.py +0 -0
  102. {code_context_control-2.143.0 → code_context_control-2.145.0}/cli/tools/ci.py +0 -0
  103. {code_context_control-2.143.0 → code_context_control-2.145.0}/cli/tools/compress.py +0 -0
  104. {code_context_control-2.143.0 → code_context_control-2.145.0}/cli/tools/delegate.py +0 -0
  105. {code_context_control-2.143.0 → code_context_control-2.145.0}/cli/tools/edit.py +0 -0
  106. {code_context_control-2.143.0 → code_context_control-2.145.0}/cli/tools/edit_verify.py +0 -0
  107. {code_context_control-2.143.0 → code_context_control-2.145.0}/cli/tools/edits.py +0 -0
  108. {code_context_control-2.143.0 → code_context_control-2.145.0}/cli/tools/federate.py +0 -0
  109. {code_context_control-2.143.0 → code_context_control-2.145.0}/cli/tools/filter.py +0 -0
  110. {code_context_control-2.143.0 → code_context_control-2.145.0}/cli/tools/impact.py +0 -0
  111. {code_context_control-2.143.0 → code_context_control-2.145.0}/cli/tools/jira.py +0 -0
  112. {code_context_control-2.143.0 → code_context_control-2.145.0}/cli/tools/locks.py +0 -0
  113. {code_context_control-2.143.0 → code_context_control-2.145.0}/cli/tools/memory.py +0 -0
  114. {code_context_control-2.143.0 → code_context_control-2.145.0}/cli/tools/override.py +0 -0
  115. {code_context_control-2.143.0 → code_context_control-2.145.0}/cli/tools/project.py +0 -0
  116. {code_context_control-2.143.0 → code_context_control-2.145.0}/cli/tools/read.py +0 -0
  117. {code_context_control-2.143.0 → code_context_control-2.145.0}/cli/tools/search.py +0 -0
  118. {code_context_control-2.143.0 → code_context_control-2.145.0}/cli/tools/session.py +0 -0
  119. {code_context_control-2.143.0 → code_context_control-2.145.0}/cli/tools/shell.py +0 -0
  120. {code_context_control-2.143.0 → code_context_control-2.145.0}/cli/tools/shell_job.py +0 -0
  121. {code_context_control-2.143.0 → code_context_control-2.145.0}/cli/tools/shell_nudge.py +0 -0
  122. {code_context_control-2.143.0 → code_context_control-2.145.0}/cli/tools/shell_parsers.py +0 -0
  123. {code_context_control-2.143.0 → code_context_control-2.145.0}/cli/tools/shell_render.py +0 -0
  124. {code_context_control-2.143.0 → code_context_control-2.145.0}/cli/tools/status.py +0 -0
  125. {code_context_control-2.143.0 → code_context_control-2.145.0}/cli/tools/tasks.py +0 -0
  126. {code_context_control-2.143.0 → code_context_control-2.145.0}/cli/tools/validate.py +0 -0
  127. {code_context_control-2.143.0 → code_context_control-2.145.0}/cli/ui/api.js +0 -0
  128. {code_context_control-2.143.0 → code_context_control-2.145.0}/cli/ui/app.js +0 -0
  129. {code_context_control-2.143.0 → code_context_control-2.145.0}/cli/ui/components/access.js +0 -0
  130. {code_context_control-2.143.0 → code_context_control-2.145.0}/cli/ui/components/bitbucket.js +0 -0
  131. {code_context_control-2.143.0 → code_context_control-2.145.0}/cli/ui/components/chat.js +0 -0
  132. {code_context_control-2.143.0 → code_context_control-2.145.0}/cli/ui/components/dashboard.js +0 -0
  133. {code_context_control-2.143.0 → code_context_control-2.145.0}/cli/ui/components/edits.js +0 -0
  134. {code_context_control-2.143.0 → code_context_control-2.145.0}/cli/ui/components/enforcement.js +0 -0
  135. {code_context_control-2.143.0 → code_context_control-2.145.0}/cli/ui/components/instructions.js +0 -0
  136. {code_context_control-2.143.0 → code_context_control-2.145.0}/cli/ui/components/jira.js +0 -0
  137. {code_context_control-2.143.0 → code_context_control-2.145.0}/cli/ui/components/memory.js +0 -0
  138. {code_context_control-2.143.0 → code_context_control-2.145.0}/cli/ui/components/sessions.js +0 -0
  139. {code_context_control-2.143.0 → code_context_control-2.145.0}/cli/ui/components/settings.js +0 -0
  140. {code_context_control-2.143.0 → code_context_control-2.145.0}/cli/ui/components/sidebar.js +0 -0
  141. {code_context_control-2.143.0 → code_context_control-2.145.0}/cli/ui/components/tasks.js +0 -0
  142. {code_context_control-2.143.0 → code_context_control-2.145.0}/cli/ui/icons.js +0 -0
  143. {code_context_control-2.143.0 → code_context_control-2.145.0}/cli/ui/pm_shared.js +0 -0
  144. {code_context_control-2.143.0 → code_context_control-2.145.0}/cli/ui/shared.js +0 -0
  145. {code_context_control-2.143.0 → code_context_control-2.145.0}/cli/ui/theme.js +0 -0
  146. {code_context_control-2.143.0 → code_context_control-2.145.0}/cli/ui.html +0 -0
  147. {code_context_control-2.143.0 → code_context_control-2.145.0}/cli/ui_legacy.html +0 -0
  148. {code_context_control-2.143.0 → code_context_control-2.145.0}/cli/ui_nano.html +0 -0
  149. {code_context_control-2.143.0 → code_context_control-2.145.0}/code_context_control.egg-info/dependency_links.txt +0 -0
  150. {code_context_control-2.143.0 → code_context_control-2.145.0}/code_context_control.egg-info/entry_points.txt +0 -0
  151. {code_context_control-2.143.0 → code_context_control-2.145.0}/code_context_control.egg-info/top_level.txt +0 -0
  152. {code_context_control-2.143.0 → code_context_control-2.145.0}/core/__init__.py +0 -0
  153. {code_context_control-2.143.0 → code_context_control-2.145.0}/core/codex_patch.py +0 -0
  154. {code_context_control-2.143.0 → code_context_control-2.145.0}/core/config.py +0 -0
  155. {code_context_control-2.143.0 → code_context_control-2.145.0}/core/grok_payload.py +0 -0
  156. {code_context_control-2.143.0 → code_context_control-2.145.0}/core/hook_command.py +0 -0
  157. {code_context_control-2.143.0 → code_context_control-2.145.0}/core/host.py +0 -0
  158. {code_context_control-2.143.0 → code_context_control-2.145.0}/core/ide.py +0 -0
  159. {code_context_control-2.143.0 → code_context_control-2.145.0}/core/mcp_toml.py +0 -0
  160. {code_context_control-2.143.0 → code_context_control-2.145.0}/core/web_security.py +0 -0
  161. {code_context_control-2.143.0 → code_context_control-2.145.0}/oracle/__init__.py +0 -0
  162. {code_context_control-2.143.0 → code_context_control-2.145.0}/oracle/config.py +0 -0
  163. {code_context_control-2.143.0 → code_context_control-2.145.0}/oracle/listeners.py +0 -0
  164. {code_context_control-2.143.0 → code_context_control-2.145.0}/oracle/mcp_oracle.py +0 -0
  165. {code_context_control-2.143.0 → code_context_control-2.145.0}/oracle/oracle_server.py +0 -0
  166. {code_context_control-2.143.0 → code_context_control-2.145.0}/oracle/oracle_ui.html +0 -0
  167. {code_context_control-2.143.0 → code_context_control-2.145.0}/oracle/services/__init__.py +0 -0
  168. {code_context_control-2.143.0 → code_context_control-2.145.0}/oracle/services/activity_reporter.py +0 -0
  169. {code_context_control-2.143.0 → code_context_control-2.145.0}/oracle/services/api_auth.py +0 -0
  170. {code_context_control-2.143.0 → code_context_control-2.145.0}/oracle/services/c3_bridge.py +0 -0
  171. {code_context_control-2.143.0 → code_context_control-2.145.0}/oracle/services/chat_engine.py +0 -0
  172. {code_context_control-2.143.0 → code_context_control-2.145.0}/oracle/services/chat_poll.py +0 -0
  173. {code_context_control-2.143.0 → code_context_control-2.145.0}/oracle/services/chat_store.py +0 -0
  174. {code_context_control-2.143.0 → code_context_control-2.145.0}/oracle/services/client_tokens.py +0 -0
  175. {code_context_control-2.143.0 → code_context_control-2.145.0}/oracle/services/cross_memory.py +0 -0
  176. {code_context_control-2.143.0 → code_context_control-2.145.0}/oracle/services/discovery_audit.py +0 -0
  177. {code_context_control-2.143.0 → code_context_control-2.145.0}/oracle/services/federated_graph.py +0 -0
  178. {code_context_control-2.143.0 → code_context_control-2.145.0}/oracle/services/health_checker.py +0 -0
  179. {code_context_control-2.143.0 → code_context_control-2.145.0}/oracle/services/insight_engine.py +0 -0
  180. {code_context_control-2.143.0 → code_context_control-2.145.0}/oracle/services/local_session.py +0 -0
  181. {code_context_control-2.143.0 → code_context_control-2.145.0}/oracle/services/memory_reader.py +0 -0
  182. {code_context_control-2.143.0 → code_context_control-2.145.0}/oracle/services/memory_writer.py +0 -0
  183. {code_context_control-2.143.0 → code_context_control-2.145.0}/oracle/services/project_scanner.py +0 -0
  184. {code_context_control-2.143.0 → code_context_control-2.145.0}/oracle/services/review_agent.py +0 -0
  185. {code_context_control-2.143.0 → code_context_control-2.145.0}/oracle/services/tool_executor.py +0 -0
  186. {code_context_control-2.143.0 → code_context_control-2.145.0}/oracle/services/tool_registry.py +0 -0
  187. {code_context_control-2.143.0 → code_context_control-2.145.0}/oracle/ui/activity.js +0 -0
  188. {code_context_control-2.143.0 → code_context_control-2.145.0}/oracle/ui/agents.js +0 -0
  189. {code_context_control-2.143.0 → code_context_control-2.145.0}/oracle/ui/app.js +0 -0
  190. {code_context_control-2.143.0 → code_context_control-2.145.0}/oracle/ui/busy.js +0 -0
  191. {code_context_control-2.143.0 → code_context_control-2.145.0}/oracle/ui/chat/conversations.js +0 -0
  192. {code_context_control-2.143.0 → code_context_control-2.145.0}/oracle/ui/chat/input.js +0 -0
  193. {code_context_control-2.143.0 → code_context_control-2.145.0}/oracle/ui/chat/markdown.js +0 -0
  194. {code_context_control-2.143.0 → code_context_control-2.145.0}/oracle/ui/chat/send.js +0 -0
  195. {code_context_control-2.143.0 → code_context_control-2.145.0}/oracle/ui/chat/stream_renderer.js +0 -0
  196. {code_context_control-2.143.0 → code_context_control-2.145.0}/oracle/ui/chat/toolbar.js +0 -0
  197. {code_context_control-2.143.0 → code_context_control-2.145.0}/oracle/ui/core.js +0 -0
  198. {code_context_control-2.143.0 → code_context_control-2.145.0}/oracle/ui/crossgraph.js +0 -0
  199. {code_context_control-2.143.0 → code_context_control-2.145.0}/oracle/ui/header.js +0 -0
  200. {code_context_control-2.143.0 → code_context_control-2.145.0}/oracle/ui/insights.js +0 -0
  201. {code_context_control-2.143.0 → code_context_control-2.145.0}/oracle/ui/projects.js +0 -0
  202. {code_context_control-2.143.0 → code_context_control-2.145.0}/oracle/ui/qrcode.js +0 -0
  203. {code_context_control-2.143.0 → code_context_control-2.145.0}/oracle/ui/settings.js +0 -0
  204. {code_context_control-2.143.0 → code_context_control-2.145.0}/oracle/ui/suggestions.js +0 -0
  205. {code_context_control-2.143.0 → code_context_control-2.145.0}/oracle/ui/theme_tabs.js +0 -0
  206. {code_context_control-2.143.0 → code_context_control-2.145.0}/services/__init__.py +0 -0
  207. {code_context_control-2.143.0 → code_context_control-2.145.0}/services/access_telemetry.py +0 -0
  208. {code_context_control-2.143.0 → code_context_control-2.145.0}/services/activity_log.py +0 -0
  209. {code_context_control-2.143.0 → code_context_control-2.145.0}/services/agent_base.py +0 -0
  210. {code_context_control-2.143.0 → code_context_control-2.145.0}/services/agent_downshift.py +0 -0
  211. {code_context_control-2.143.0 → code_context_control-2.145.0}/services/agent_locks.py +0 -0
  212. {code_context_control-2.143.0 → code_context_control-2.145.0}/services/agents.py +0 -0
  213. {code_context_control-2.143.0 → code_context_control-2.145.0}/services/agents_workflow.py +0 -0
  214. {code_context_control-2.143.0 → code_context_control-2.145.0}/services/artifact_defs.py +0 -0
  215. {code_context_control-2.143.0 → code_context_control-2.145.0}/services/artifact_store.py +0 -0
  216. {code_context_control-2.143.0 → code_context_control-2.145.0}/services/atomic_json.py +0 -0
  217. {code_context_control-2.143.0 → code_context_control-2.145.0}/services/auto_memory.py +0 -0
  218. {code_context_control-2.143.0 → code_context_control-2.145.0}/services/background_service.py +0 -0
  219. {code_context_control-2.143.0 → code_context_control-2.145.0}/services/bench/__init__.py +0 -0
  220. {code_context_control-2.143.0 → code_context_control-2.145.0}/services/bench/delegate_eval.py +0 -0
  221. {code_context_control-2.143.0 → code_context_control-2.145.0}/services/bench/delegate_write_eval.py +0 -0
  222. {code_context_control-2.143.0 → code_context_control-2.145.0}/services/bench/external/__init__.py +0 -0
  223. {code_context_control-2.143.0 → code_context_control-2.145.0}/services/bench/external/aider_polyglot.py +0 -0
  224. {code_context_control-2.143.0 → code_context_control-2.145.0}/services/bench/external/swe_bench.py +0 -0
  225. {code_context_control-2.143.0 → code_context_control-2.145.0}/services/bench/map_eval.py +0 -0
  226. {code_context_control-2.143.0 → code_context_control-2.145.0}/services/bench/search_eval.py +0 -0
  227. {code_context_control-2.143.0 → code_context_control-2.145.0}/services/bench/shell_eval.py +0 -0
  228. {code_context_control-2.143.0 → code_context_control-2.145.0}/services/benchmark_dashboard.py +0 -0
  229. {code_context_control-2.143.0 → code_context_control-2.145.0}/services/bitbucket_client.py +0 -0
  230. {code_context_control-2.143.0 → code_context_control-2.145.0}/services/bitbucket_credentials.py +0 -0
  231. {code_context_control-2.143.0 → code_context_control-2.145.0}/services/ci_act.py +0 -0
  232. {code_context_control-2.143.0 → code_context_control-2.145.0}/services/ci_cache.py +0 -0
  233. {code_context_control-2.143.0 → code_context_control-2.145.0}/services/ci_expr.py +0 -0
  234. {code_context_control-2.143.0 → code_context_control-2.145.0}/services/ci_failures.py +0 -0
  235. {code_context_control-2.143.0 → code_context_control-2.145.0}/services/ci_github.py +0 -0
  236. {code_context_control-2.143.0 → code_context_control-2.145.0}/services/ci_impact.py +0 -0
  237. {code_context_control-2.143.0 → code_context_control-2.145.0}/services/ci_intel.py +0 -0
  238. {code_context_control-2.143.0 → code_context_control-2.145.0}/services/ci_runner.py +0 -0
  239. {code_context_control-2.143.0 → code_context_control-2.145.0}/services/ci_workflow.py +0 -0
  240. {code_context_control-2.143.0 → code_context_control-2.145.0}/services/circuit_breaker.py +0 -0
  241. {code_context_control-2.143.0 → code_context_control-2.145.0}/services/claude_md.py +0 -0
  242. {code_context_control-2.143.0 → code_context_control-2.145.0}/services/codex_integration.py +0 -0
  243. {code_context_control-2.143.0 → code_context_control-2.145.0}/services/codex_transcript.py +0 -0
  244. {code_context_control-2.143.0 → code_context_control-2.145.0}/services/compressor.py +0 -0
  245. {code_context_control-2.143.0 → code_context_control-2.145.0}/services/context_snapshot.py +0 -0
  246. {code_context_control-2.143.0 → code_context_control-2.145.0}/services/conversation_store.py +0 -0
  247. {code_context_control-2.143.0 → code_context_control-2.145.0}/services/cred_audit.py +0 -0
  248. {code_context_control-2.143.0 → code_context_control-2.145.0}/services/cred_telemetry.py +0 -0
  249. {code_context_control-2.143.0 → code_context_control-2.145.0}/services/delegate_agents.py +0 -0
  250. {code_context_control-2.143.0 → code_context_control-2.145.0}/services/delegate_hints.py +0 -0
  251. {code_context_control-2.143.0 → code_context_control-2.145.0}/services/delegate_write.py +0 -0
  252. {code_context_control-2.143.0 → code_context_control-2.145.0}/services/dir_map.py +0 -0
  253. {code_context_control-2.143.0 → code_context_control-2.145.0}/services/doc_index.py +0 -0
  254. {code_context_control-2.143.0 → code_context_control-2.145.0}/services/e2e_benchmark.py +0 -0
  255. {code_context_control-2.143.0 → code_context_control-2.145.0}/services/e2e_evaluator.py +0 -0
  256. {code_context_control-2.143.0 → code_context_control-2.145.0}/services/e2e_tasks.py +0 -0
  257. {code_context_control-2.143.0 → code_context_control-2.145.0}/services/edit_ledger.py +0 -0
  258. {code_context_control-2.143.0 → code_context_control-2.145.0}/services/embedding_index.py +0 -0
  259. {code_context_control-2.143.0 → code_context_control-2.145.0}/services/enforcement_policy.py +0 -0
  260. {code_context_control-2.143.0 → code_context_control-2.145.0}/services/error_reporting.py +0 -0
  261. {code_context_control-2.143.0 → code_context_control-2.145.0}/services/file_map.py +0 -0
  262. {code_context_control-2.143.0 → code_context_control-2.145.0}/services/file_memory.py +0 -0
  263. {code_context_control-2.143.0 → code_context_control-2.145.0}/services/git_context.py +0 -0
  264. {code_context_control-2.143.0 → code_context_control-2.145.0}/services/grok_integration.py +0 -0
  265. {code_context_control-2.143.0 → code_context_control-2.145.0}/services/grok_transcript.py +0 -0
  266. {code_context_control-2.143.0 → code_context_control-2.145.0}/services/host_sessions.py +0 -0
  267. {code_context_control-2.143.0 → code_context_control-2.145.0}/services/hub_service.py +0 -0
  268. {code_context_control-2.143.0 → code_context_control-2.145.0}/services/index_store.py +0 -0
  269. {code_context_control-2.143.0 → code_context_control-2.145.0}/services/indexer.py +0 -0
  270. {code_context_control-2.143.0 → code_context_control-2.145.0}/services/jira_client.py +0 -0
  271. {code_context_control-2.143.0 → code_context_control-2.145.0}/services/jira_cloud.py +0 -0
  272. {code_context_control-2.143.0 → code_context_control-2.145.0}/services/jira_credentials.py +0 -0
  273. {code_context_control-2.143.0 → code_context_control-2.145.0}/services/jira_data_center.py +0 -0
  274. {code_context_control-2.143.0 → code_context_control-2.145.0}/services/jira_links.py +0 -0
  275. {code_context_control-2.143.0 → code_context_control-2.145.0}/services/lexical_index.py +0 -0
  276. {code_context_control-2.143.0 → code_context_control-2.145.0}/services/mask_activation.py +0 -0
  277. {code_context_control-2.143.0 → code_context_control-2.145.0}/services/mask_mirror.py +0 -0
  278. {code_context_control-2.143.0 → code_context_control-2.145.0}/services/mask_presets.py +0 -0
  279. {code_context_control-2.143.0 → code_context_control-2.145.0}/services/memory.py +0 -0
  280. {code_context_control-2.143.0 → code_context_control-2.145.0}/services/memory_consolidator.py +0 -0
  281. {code_context_control-2.143.0 → code_context_control-2.145.0}/services/memory_distiller.py +0 -0
  282. {code_context_control-2.143.0 → code_context_control-2.145.0}/services/memory_graph.py +0 -0
  283. {code_context_control-2.143.0 → code_context_control-2.145.0}/services/memory_grounder.py +0 -0
  284. {code_context_control-2.143.0 → code_context_control-2.145.0}/services/memory_queue.py +0 -0
  285. {code_context_control-2.143.0 → code_context_control-2.145.0}/services/memory_scorer.py +0 -0
  286. {code_context_control-2.143.0 → code_context_control-2.145.0}/services/metrics.py +0 -0
  287. {code_context_control-2.143.0 → code_context_control-2.145.0}/services/notifications.py +0 -0
  288. {code_context_control-2.143.0 → code_context_control-2.145.0}/services/ollama_bridge.py +0 -0
  289. {code_context_control-2.143.0 → code_context_control-2.145.0}/services/ollama_client.py +0 -0
  290. {code_context_control-2.143.0 → code_context_control-2.145.0}/services/ollama_credentials.py +0 -0
  291. {code_context_control-2.143.0 → code_context_control-2.145.0}/services/oracle_service.py +0 -0
  292. {code_context_control-2.143.0 → code_context_control-2.145.0}/services/output_filter.py +0 -0
  293. {code_context_control-2.143.0 → code_context_control-2.145.0}/services/override_costs.py +0 -0
  294. {code_context_control-2.143.0 → code_context_control-2.145.0}/services/override_grants.py +0 -0
  295. {code_context_control-2.143.0 → code_context_control-2.145.0}/services/override_requests.py +0 -0
  296. {code_context_control-2.143.0 → code_context_control-2.145.0}/services/override_wake.py +0 -0
  297. {code_context_control-2.143.0 → code_context_control-2.145.0}/services/parser.py +0 -0
  298. {code_context_control-2.143.0 → code_context_control-2.145.0}/services/project_manager.py +0 -0
  299. {code_context_control-2.143.0 → code_context_control-2.145.0}/services/project_runtime.py +0 -0
  300. {code_context_control-2.143.0 → code_context_control-2.145.0}/services/protocol.py +0 -0
  301. {code_context_control-2.143.0 → code_context_control-2.145.0}/services/proxy_state.py +0 -0
  302. {code_context_control-2.143.0 → code_context_control-2.145.0}/services/repo_map.py +0 -0
  303. {code_context_control-2.143.0 → code_context_control-2.145.0}/services/repo_shape.py +0 -0
  304. {code_context_control-2.143.0 → code_context_control-2.145.0}/services/reranker.py +0 -0
  305. {code_context_control-2.143.0 → code_context_control-2.145.0}/services/retention.py +0 -0
  306. {code_context_control-2.143.0 → code_context_control-2.145.0}/services/retrieval.py +0 -0
  307. {code_context_control-2.143.0 → code_context_control-2.145.0}/services/retrieval_broker.py +0 -0
  308. {code_context_control-2.143.0 → code_context_control-2.145.0}/services/router.py +0 -0
  309. {code_context_control-2.143.0 → code_context_control-2.145.0}/services/runtime.py +0 -0
  310. {code_context_control-2.143.0 → code_context_control-2.145.0}/services/scanner.py +0 -0
  311. {code_context_control-2.143.0 → code_context_control-2.145.0}/services/session_benchmark.py +0 -0
  312. {code_context_control-2.143.0 → code_context_control-2.145.0}/services/session_catalog.py +0 -0
  313. {code_context_control-2.143.0 → code_context_control-2.145.0}/services/session_live.py +0 -0
  314. {code_context_control-2.143.0 → code_context_control-2.145.0}/services/session_manager.py +0 -0
  315. {code_context_control-2.143.0 → code_context_control-2.145.0}/services/session_preloader.py +0 -0
  316. {code_context_control-2.143.0 → code_context_control-2.145.0}/services/shell_jobs.py +0 -0
  317. {code_context_control-2.143.0 → code_context_control-2.145.0}/services/shell_output.py +0 -0
  318. {code_context_control-2.143.0 → code_context_control-2.145.0}/services/subprojects.py +0 -0
  319. {code_context_control-2.143.0 → code_context_control-2.145.0}/services/task_store.py +0 -0
  320. {code_context_control-2.143.0 → code_context_control-2.145.0}/services/telemetry.py +0 -0
  321. {code_context_control-2.143.0 → code_context_control-2.145.0}/services/terminal_launch.py +0 -0
  322. {code_context_control-2.143.0 → code_context_control-2.145.0}/services/text_index.py +0 -0
  323. {code_context_control-2.143.0 → code_context_control-2.145.0}/services/time_tracker.py +0 -0
  324. {code_context_control-2.143.0 → code_context_control-2.145.0}/services/tool_classifier.py +0 -0
  325. {code_context_control-2.143.0 → code_context_control-2.145.0}/services/transcript_index.py +0 -0
  326. {code_context_control-2.143.0 → code_context_control-2.145.0}/services/validation_cache.py +0 -0
  327. {code_context_control-2.143.0 → code_context_control-2.145.0}/services/vector_store.py +0 -0
  328. {code_context_control-2.143.0 → code_context_control-2.145.0}/services/watcher.py +0 -0
  329. {code_context_control-2.143.0 → code_context_control-2.145.0}/services/win_subprocess.py +0 -0
  330. {code_context_control-2.143.0 → code_context_control-2.145.0}/setup.cfg +0 -0
  331. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_access_builtin_optout.py +0 -0
  332. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_access_guard.py +0 -0
  333. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_access_guard_meta.py +0 -0
  334. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_access_guard_shell_project.py +0 -0
  335. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_access_guard_surfaces.py +0 -0
  336. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_access_guard_wiring.py +0 -0
  337. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_activity_log_find_last.py +0 -0
  338. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_activity_reporter.py +0 -0
  339. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_agent_locks.py +0 -0
  340. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_aider_polyglot.py +0 -0
  341. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_antigravity_transition.py +0 -0
  342. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_artifact_store.py +0 -0
  343. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_artifact_tool.py +0 -0
  344. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_atomic_json.py +0 -0
  345. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_background_service.py +0 -0
  346. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_bitbucket_cli_smoke.py +0 -0
  347. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_bitbucket_client.py +0 -0
  348. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_bitbucket_config_fallback.py +0 -0
  349. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_bitbucket_credentials.py +0 -0
  350. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_bitbucket_tool.py +0 -0
  351. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_builtin_modes.py +0 -0
  352. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_c3_bridge_project_artifacts.py +0 -0
  353. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_c3_shell.py +0 -0
  354. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_chat_poll.py +0 -0
  355. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_ci_act.py +0 -0
  356. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_ci_cache.py +0 -0
  357. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_ci_dag_ownership.py +0 -0
  358. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_ci_expr.py +0 -0
  359. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_ci_impact.py +0 -0
  360. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_ci_intel.py +0 -0
  361. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_ci_runner.py +0 -0
  362. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_ci_workflow.py +0 -0
  363. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_circuit_breaker.py +0 -0
  364. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_claude_md_merge.py +0 -0
  365. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_claude_md_updater.py +0 -0
  366. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_cli_smoke.py +0 -0
  367. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_codex_mcp_transport.py +0 -0
  368. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_codex_native.py +0 -0
  369. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_compressor_large_file.py +0 -0
  370. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_confirm_guard.py +0 -0
  371. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_confirm_guard_wiring.py +0 -0
  372. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_cooccurrence_bounds.py +0 -0
  373. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_cred_audit.py +0 -0
  374. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_cred_telemetry.py +0 -0
  375. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_credential_login_kind.py +0 -0
  376. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_credential_ui_parity.py +0 -0
  377. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_delegate_adoption_d4.py +0 -0
  378. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_delegate_auto.py +0 -0
  379. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_delegate_cascade.py +0 -0
  380. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_delegate_claude_d1.py +0 -0
  381. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_delegate_eval.py +0 -0
  382. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_delegate_grok.py +0 -0
  383. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_delegate_host_d2.py +0 -0
  384. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_delegate_scout_d3.py +0 -0
  385. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_delegate_telemetry_d0.py +0 -0
  386. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_delegate_thinking_cap.py +0 -0
  387. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_delegate_tuning.py +0 -0
  388. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_delegate_version_probe.py +0 -0
  389. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_delegate_write.py +0 -0
  390. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_delegate_write_eval.py +0 -0
  391. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_dir_map_c3.py +0 -0
  392. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_e2e_benchmark.py +0 -0
  393. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_edit_ledger_deadline.py +0 -0
  394. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_edit_ledger_hook.py +0 -0
  395. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_edit_locking.py +0 -0
  396. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_edit_normalization.py +0 -0
  397. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_edit_verify.py +0 -0
  398. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_embedding_index_deadlock.py +0 -0
  399. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_enforcement_flip.py +0 -0
  400. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_enforcement_policy.py +0 -0
  401. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_enforcement_routes.py +0 -0
  402. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_env_parser.py +0 -0
  403. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_failed_calls_do_not_unlock.py +0 -0
  404. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_federated_graph.py +0 -0
  405. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_file_map_c1.py +0 -0
  406. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_filter_backoff.py +0 -0
  407. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_ghost_files.py +0 -0
  408. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_ghost_generation.py +0 -0
  409. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_git_branch_awareness.py +0 -0
  410. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_grok_native.py +0 -0
  411. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_hook_access_guard.py +0 -0
  412. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_hook_codex_compat.py +0 -0
  413. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_hook_dispatch.py +0 -0
  414. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_hook_grok_compat.py +0 -0
  415. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_hook_pretool_enforce.py +0 -0
  416. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_hook_prompt_recall.py +0 -0
  417. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_hook_session_end.py +0 -0
  418. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_hook_smoke.py +0 -0
  419. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_hook_state.py +0 -0
  420. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_hook_utf8_stdio.py +0 -0
  421. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_hub_access_routes.py +0 -0
  422. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_hub_credentials_route.py +0 -0
  423. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_hub_enforcement_routes.py +0 -0
  424. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_hub_hook_migration.py +0 -0
  425. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_hub_inspect_api.py +0 -0
  426. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_hub_locks_routes.py +0 -0
  427. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_hub_oracle_service_routes.py +0 -0
  428. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_hub_override_policy_routes.py +0 -0
  429. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_hub_override_routes.py +0 -0
  430. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_hub_rules_routes.py +0 -0
  431. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_hub_server_smoke.py +0 -0
  432. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_hub_sessions_routes.py +0 -0
  433. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_hub_subproject_links.py +0 -0
  434. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_ide_workflow_adaptation.py +0 -0
  435. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_index_cap_not_hardcoded.py +0 -0
  436. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_init_clear_preserves_user_content.py +0 -0
  437. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_init_scan.py +0 -0
  438. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_install_mcp_entrypoint.py +0 -0
  439. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_jira_cli_smoke.py +0 -0
  440. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_jira_client.py +0 -0
  441. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_jira_config_fallback.py +0 -0
  442. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_jira_credentials.py +0 -0
  443. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_jira_links.py +0 -0
  444. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_jira_routes.py +0 -0
  445. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_jira_tool.py +0 -0
  446. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_large_files_c4.py +0 -0
  447. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_lazy_store_init.py +0 -0
  448. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_map_eval.py +0 -0
  449. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_map_telemetry_c0.py +0 -0
  450. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_mask_guard.py +0 -0
  451. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_mask_routes.py +0 -0
  452. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_mask_surfaces.py +0 -0
  453. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_mcp_host_guard.py +0 -0
  454. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_mcp_memory_timeout.py +0 -0
  455. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_mcp_server_smoke.py +0 -0
  456. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_mcp_toml.py +0 -0
  457. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_memory_distiller.py +0 -0
  458. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_memory_graph_api.py +0 -0
  459. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_memory_queue.py +0 -0
  460. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_memory_system.py +0 -0
  461. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_mobile_api.py +0 -0
  462. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_mobile_clients.py +0 -0
  463. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_mobile_extras.py +0 -0
  464. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_mobile_jobs_ci.py +0 -0
  465. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_mobile_override_costs.py +0 -0
  466. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_mobile_override_routes.py +0 -0
  467. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_no_stale_model_pins.py +0 -0
  468. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_notification_dedup.py +0 -0
  469. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_notification_discipline.py +0 -0
  470. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_notification_kinds.py +0 -0
  471. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_ollama_credentials.py +0 -0
  472. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_oracle_api_auth.py +0 -0
  473. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_oracle_apikey_api.py +0 -0
  474. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_oracle_c3_bridge.py +0 -0
  475. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_oracle_chat_engine.py +0 -0
  476. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_oracle_chat_store.py +0 -0
  477. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_oracle_discovery_api.py +0 -0
  478. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_oracle_discovery_audit.py +0 -0
  479. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_oracle_health_probe.py +0 -0
  480. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_oracle_local_auth.py +0 -0
  481. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_oracle_loopback.py +0 -0
  482. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_oracle_ollama_bridge.py +0 -0
  483. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_oracle_scanner_cache.py +0 -0
  484. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_oracle_security_fixes.py +0 -0
  485. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_oracle_session_bootstrap.py +0 -0
  486. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_oracle_subproject_awareness.py +0 -0
  487. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_oracle_ui_bundle.py +0 -0
  488. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_output_filter.py +0 -0
  489. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_override_costs.py +0 -0
  490. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_override_grants.py +0 -0
  491. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_override_grants_mcp.py +0 -0
  492. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_override_requests.py +0 -0
  493. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_override_wake.py +0 -0
  494. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_permissions.py +0 -0
  495. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_pm_api.py +0 -0
  496. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_project_manager.py +0 -0
  497. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_project_manager_merge.py +0 -0
  498. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_project_tool.py +0 -0
  499. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_read_coercion.py +0 -0
  500. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_read_edit_parity.py +0 -0
  501. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_read_outside_root.py +0 -0
  502. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_related_facts.py +0 -0
  503. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_repo_map.py +0 -0
  504. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_repo_shape.py +0 -0
  505. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_response_boilerplate.py +0 -0
  506. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_retention.py +0 -0
  507. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_review_digest.py +0 -0
  508. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_search_eval.py +0 -0
  509. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_search_p1.py +0 -0
  510. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_search_p2.py +0 -0
  511. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_search_p2b.py +0 -0
  512. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_search_p3.py +0 -0
  513. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_search_p4.py +0 -0
  514. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_search_p5.py +0 -0
  515. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_service_durability.py +0 -0
  516. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_session_benchmark.py +0 -0
  517. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_session_budget.py +0 -0
  518. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_session_catalog.py +0 -0
  519. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_session_live.py +0 -0
  520. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_session_tool.py +0 -0
  521. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_shell_budget_s1.py +0 -0
  522. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_shell_creds.py +0 -0
  523. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_shell_eval.py +0 -0
  524. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_shell_jobs_s3.py +0 -0
  525. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_shell_nudge_s4.py +0 -0
  526. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_shell_output.py +0 -0
  527. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_shell_parsers_s2.py +0 -0
  528. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_shell_robustness.py +0 -0
  529. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_shell_telemetry_s0.py +0 -0
  530. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_shell_write_ledger.py +0 -0
  531. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_shell_writes.py +0 -0
  532. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_subproject_clear_scope.py +0 -0
  533. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_subproject_depth_consumers.py +0 -0
  534. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_subproject_exclusion.py +0 -0
  535. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_subproject_federation.py +0 -0
  536. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_subproject_linkage_api.py +0 -0
  537. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_subprojects.py +0 -0
  538. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_swe_bench.py +0 -0
  539. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_task_store.py +0 -0
  540. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_task_tool.py +0 -0
  541. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_time_tracker.py +0 -0
  542. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_token_telemetry.py +0 -0
  543. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_token_tracking.py +0 -0
  544. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_tool_registry.py +0 -0
  545. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_ui_jsx_syntax.py +0 -0
  546. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_upgrade_and_version.py +0 -0
  547. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_validate.py +0 -0
  548. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_vault_write_guard.py +0 -0
  549. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_version_sync.py +0 -0
  550. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_watcher_pruning.py +0 -0
  551. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_web_security.py +0 -0
  552. {code_context_control-2.143.0 → code_context_control-2.145.0}/tests/test_windows_reliability.py +0 -0
  553. {code_context_control-2.143.0 → code_context_control-2.145.0}/tui/__init__.py +0 -0
  554. {code_context_control-2.143.0 → code_context_control-2.145.0}/tui/backend.py +0 -0
  555. {code_context_control-2.143.0 → code_context_control-2.145.0}/tui/main.py +0 -0
  556. {code_context_control-2.143.0 → code_context_control-2.145.0}/tui/screens/__init__.py +0 -0
  557. {code_context_control-2.143.0 → code_context_control-2.145.0}/tui/screens/benchmark_view.py +0 -0
  558. {code_context_control-2.143.0 → code_context_control-2.145.0}/tui/screens/claudemd_view.py +0 -0
  559. {code_context_control-2.143.0 → code_context_control-2.145.0}/tui/screens/compress_view.py +0 -0
  560. {code_context_control-2.143.0 → code_context_control-2.145.0}/tui/screens/index_view.py +0 -0
  561. {code_context_control-2.143.0 → code_context_control-2.145.0}/tui/screens/init_view.py +0 -0
  562. {code_context_control-2.143.0 → code_context_control-2.145.0}/tui/screens/mcp_view.py +0 -0
  563. {code_context_control-2.143.0 → code_context_control-2.145.0}/tui/screens/optimize_view.py +0 -0
  564. {code_context_control-2.143.0 → code_context_control-2.145.0}/tui/screens/pipe_view.py +0 -0
  565. {code_context_control-2.143.0 → code_context_control-2.145.0}/tui/screens/projects_view.py +0 -0
  566. {code_context_control-2.143.0 → code_context_control-2.145.0}/tui/screens/search_view.py +0 -0
  567. {code_context_control-2.143.0 → code_context_control-2.145.0}/tui/screens/session_view.py +0 -0
  568. {code_context_control-2.143.0 → code_context_control-2.145.0}/tui/screens/stats.py +0 -0
  569. {code_context_control-2.143.0 → code_context_control-2.145.0}/tui/screens/ui_view.py +0 -0
  570. {code_context_control-2.143.0 → code_context_control-2.145.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.143.0
3
+ Version: 2.145.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
@@ -44,6 +44,7 @@ Requires-Dist: rich>=13.0.0
44
44
  Requires-Dist: click>=8.0.0
45
45
  Requires-Dist: pyyaml>=6.0.0
46
46
  Requires-Dist: keyring>=24.0
47
+ Requires-Dist: cryptography>=41.0
47
48
  Provides-Extra: vector
48
49
  Requires-Dist: scikit-learn>=1.3.0; extra == "vector"
49
50
  Requires-Dist: numpy>=1.24.0; extra == "vector"
@@ -91,7 +91,7 @@ console = Console() if HAS_RICH else None
91
91
  # Config
92
92
  CONFIG_DIR = ".c3"
93
93
  CONFIG_FILE = ".c3/config.json"
94
- __version__ = "2.143.0"
94
+ __version__ = "2.145.0"
95
95
 
96
96
  # The PreToolUse matcher for native subagent calls (installer and hub migration).
97
97
  AGENT_MATCHER = "Agent|Task"
@@ -6371,7 +6371,7 @@ def cmd_creds(args):
6371
6371
  """Credential vault management (global + per-project scopes)."""
6372
6372
  sub = getattr(args, "creds_cmd", None)
6373
6373
  if not sub:
6374
- print("Usage: c3 creds {set,get,list,rm,import,usage,audit} [args]")
6374
+ print("Usage: c3 creds {set,get,list,rm,import,usage,audit,backup} [args]")
6375
6375
  return
6376
6376
 
6377
6377
  project_path = getattr(args, "project_path", ".") or "."
@@ -6390,6 +6390,8 @@ def cmd_creds(args):
6390
6390
  _creds_cmd_usage(args, project_path)
6391
6391
  elif sub == "audit":
6392
6392
  _creds_cmd_audit(args, project_path)
6393
+ elif sub == "backup":
6394
+ _creds_cmd_backup(args, project_path)
6393
6395
  else:
6394
6396
  print(f"Unknown creds subcommand: {sub}")
6395
6397
 
@@ -6398,11 +6400,12 @@ def _creds_scope(args) -> str:
6398
6400
  return "global" if getattr(args, "use_global", False) else "project"
6399
6401
 
6400
6402
 
6401
- def _creds_entry_line(name: str, entry: dict) -> str:
6403
+ def _creds_entry_line(name: str, entry: dict, missing: bool = False) -> str:
6402
6404
  flags = [f for f in ("inject", "agent_readable") if entry.get(f)]
6405
+ size = "VALUE MISSING" if missing else f"len={entry.get('value_len', '?')}"
6403
6406
  parts = [
6404
6407
  f"{name:<24} {entry.get('scope', '?'):<8} {entry.get('type', 'token'):<10}"
6405
- f" len={entry.get('value_len', '?')}",
6408
+ f" {size}",
6406
6409
  ]
6407
6410
  display = entry.get("display") or {}
6408
6411
  if display:
@@ -6465,13 +6468,15 @@ def _creds_cmd_set(args, project_path: str) -> None:
6465
6468
 
6466
6469
  from services import credential_store as cred_store
6467
6470
 
6468
- ctype = getattr(args, "ctype", "token") or "token"
6471
+ ctype = getattr(args, "ctype", None)
6472
+ prompt_type = ctype or cred_store.get_entry(
6473
+ args.name, project_path=project_path).get("type", "token")
6469
6474
  value = getattr(args, "value", "") or ""
6470
6475
  if getattr(args, "stdin", False):
6471
6476
  value = sys.stdin.read().rstrip("\n")
6472
6477
  if not value:
6473
- if ctype in cred_store.STRUCTURED_TYPES:
6474
- value = _creds_prompt_structured(args.name, ctype)
6478
+ if prompt_type in cred_store.STRUCTURED_TYPES:
6479
+ value = _creds_prompt_structured(args.name, prompt_type)
6475
6480
  if value == "{}":
6476
6481
  print("Cancelled -- no fields entered.")
6477
6482
  return
@@ -6485,11 +6490,11 @@ def _creds_cmd_set(args, project_path: str) -> None:
6485
6490
  entry = cred_store.set_credential(
6486
6491
  args.name, value,
6487
6492
  scope=scope, project_path=project_path,
6488
- description=getattr(args, "desc", "") or "",
6493
+ description=getattr(args, "desc", None),
6489
6494
  ctype=ctype,
6490
- env_var=getattr(args, "env_var", "") or "",
6491
- agent_readable=bool(getattr(args, "agent_readable", False)),
6492
- inject=bool(getattr(args, "inject", False)),
6495
+ env_var=getattr(args, "env_var", None),
6496
+ agent_readable=getattr(args, "agent_readable", None),
6497
+ inject=getattr(args, "inject", None),
6493
6498
  )
6494
6499
  except (cred_store.CredentialError, RuntimeError) as exc:
6495
6500
  print(f"[error] {exc}")
@@ -6499,6 +6504,111 @@ def _creds_cmd_set(args, project_path: str) -> None:
6499
6504
  if entry["agent_readable"]:
6500
6505
  print("[warn] agent_readable=true -- the agent can read this value "
6501
6506
  "into its context and transcripts.")
6507
+ _creds_print_backup_note(entry.get("backup", ""))
6508
+
6509
+
6510
+ def _creds_print_backup_note(backup: str) -> None:
6511
+ if backup == "off":
6512
+ print("[note] no vault backup: this value exists only in the OS keychain. "
6513
+ "`c3 creds backup init` keeps a copy that survives a keychain wipe.")
6514
+ elif backup.startswith("failed"):
6515
+ print(f"[warn] the vault backup was not updated ({backup}); "
6516
+ "run `c3 creds backup sync`.")
6517
+
6518
+
6519
+ def _creds_known_projects(project_path: str) -> list:
6520
+ """The current project plus every project the hub knows about."""
6521
+ from services.project_manager import ProjectManager
6522
+ paths = [str(Path(project_path).resolve())]
6523
+ paths += [str(p.get("path")) for p in ProjectManager().list_projects()
6524
+ if p.get("path")]
6525
+ return paths
6526
+
6527
+
6528
+ def _creds_read_passphrase(prompt: str, *, confirm: bool = False) -> str:
6529
+ import getpass
6530
+ first = getpass.getpass(prompt)
6531
+ if confirm and getpass.getpass("Repeat it: ") != first:
6532
+ print("[error] the passphrases did not match -- nothing changed.")
6533
+ return ""
6534
+ return first
6535
+
6536
+
6537
+ def _creds_cmd_backup(args, project_path: str) -> None:
6538
+ from services import credential_backup as backup
6539
+
6540
+ action = args.backup_cmd
6541
+ if action in ("init", "restore", "passphrase") and not sys.stdin.isatty():
6542
+ print("[error] run this in your own terminal: the passphrase is read from "
6543
+ "the keyboard, never from a pipe or an argument.")
6544
+ return
6545
+ try:
6546
+ if action == "init":
6547
+ print("Choose a passphrase for the vault backup. Without it the backup "
6548
+ "cannot be opened -- keep it in your password manager.")
6549
+ passphrase = _creds_read_passphrase(
6550
+ f"New passphrase (min {backup.MIN_PASSPHRASE} chars): ", confirm=True)
6551
+ if not passphrase:
6552
+ return
6553
+ backup.init(passphrase)
6554
+ done = backup.sync(_creds_known_projects(project_path))
6555
+ print(f"[OK] Vault backup on: {backup.backup_path()} -- "
6556
+ f"{done['saved']} value(s) copied. Every value you set from now "
6557
+ "on is copied automatically.")
6558
+ if done["missing"]:
6559
+ print(f" no value to copy (re-enter these): {', '.join(done['missing'])}")
6560
+ elif action == "sync":
6561
+ done = backup.sync(_creds_known_projects(project_path))
6562
+ print(f"[OK] {done['saved']} value(s) copied to the vault backup.")
6563
+ for label, names in (("no value to copy", done["missing"]),
6564
+ ("failed", done["failed"])):
6565
+ if names:
6566
+ print(f" {label}: {', '.join(names)}")
6567
+ elif action == "status":
6568
+ st = backup.status(_creds_known_projects(project_path))
6569
+ if st["enabled"]:
6570
+ print(f"Vault backup: on ({st['path']}, created {st['created']}) -- "
6571
+ f"{st['backed_up']} value(s) held.")
6572
+ else:
6573
+ print("Vault backup: off -- values live only in the OS keychain. "
6574
+ "Turn it on with `c3 creds backup init`.")
6575
+ for label, key in (("restorable (`c3 creds backup restore`)", "restorable"),
6576
+ ("lost, no copy (re-enter with `c3 creds set`)", "lost"),
6577
+ ("not backed up yet (`c3 creds backup sync`)", "not_backed_up")):
6578
+ if st[key] and (st["enabled"] or key == "lost"):
6579
+ print(f" {label}: {', '.join(st[key])}")
6580
+ elif action == "restore":
6581
+ passphrase = _creds_read_passphrase("Backup passphrase: ")
6582
+ only = [n.strip() for n in (args.only or "").split(",") if n.strip()]
6583
+ out = backup.restore(passphrase, only=only or None)
6584
+ print(f"[OK] Restored {len(out['restored'])} value(s)"
6585
+ + (f": {', '.join(out['restored'])}" if out["restored"] else "."))
6586
+ for label, key in (("still in the keychain, left alone", "present"),
6587
+ ("entry or project gone, skipped", "orphaned"),
6588
+ ("failed", "failed")):
6589
+ if out[key]:
6590
+ print(f" {label}: {', '.join(out[key])}")
6591
+ if out["restored"]:
6592
+ _creds_log_restore(out["restored"])
6593
+ else: # passphrase
6594
+ old = _creds_read_passphrase("Current passphrase: ")
6595
+ new = _creds_read_passphrase(
6596
+ f"New passphrase (min {backup.MIN_PASSPHRASE} chars): ", confirm=True)
6597
+ if old and new:
6598
+ backup.change_passphrase(old, new)
6599
+ print("[OK] Backup passphrase changed.")
6600
+ except backup.BackupError as exc:
6601
+ print(f"[error] {exc}")
6602
+
6603
+
6604
+ def _creds_log_restore(names: list) -> None:
6605
+ """Names only, to the global activity log that `c3 creds audit` reads."""
6606
+ from services import credential_store as cred_store
6607
+ from services.activity_log import ActivityLog
6608
+ home = cred_store.global_base()
6609
+ if home is not None:
6610
+ ActivityLog(str(home)).log("cred_action", {
6611
+ "kind": "creds", "action": "restore", "names": names, "via": "cli"})
6502
6612
 
6503
6613
 
6504
6614
  def _creds_count_show(refs, project_path: str) -> None:
@@ -6575,8 +6685,17 @@ def _creds_cmd_list(args, project_path: str) -> None:
6575
6685
  "(add --global for all projects).")
6576
6686
  return
6577
6687
  print(f"{len(entries)} credential(s) — project scope shadows global:")
6688
+ missing = 0
6578
6689
  for name, entry in entries.items():
6579
- print(" " + _creds_entry_line(name, entry))
6690
+ gone = not cred_store.is_resolvable(
6691
+ name, project_path=project_path, scope=entry["scope"])
6692
+ missing += gone
6693
+ print(" " + _creds_entry_line(name, entry, gone))
6694
+ if missing:
6695
+ print(f"\n{missing} entr{'y has' if missing == 1 else 'ies have'} no stored "
6696
+ "value (the OS keychain no longer holds it). Re-enter with "
6697
+ "`c3 creds set NAME` (add --global for global entries); the "
6698
+ "entry keeps its env var, description and flags.")
6580
6699
 
6581
6700
 
6582
6701
  def _creds_cmd_rm(args, project_path: str) -> None:
@@ -520,16 +520,21 @@ def build_parser(version: str, parse_cli_ide_arg):
520
520
  cr_set.add_argument("name", help="Entry name (env-var safe: [A-Za-z_][A-Za-z0-9_]*)")
521
521
  cr_set.add_argument("--value", default="", help="Secret value (prompted via getpass if omitted — preferred). Structured types take a JSON object of fields")
522
522
  cr_set.add_argument("--stdin", action="store_true", help="Read the value from stdin (piped/multiline values)")
523
+ # Every metadata option defaults to None = keep what an existing entry
524
+ # has, so re-entering a value does not reset its settings.
523
525
  cr_set.add_argument("--type", dest="ctype",
524
526
  choices=["token", "env", "multiline",
525
527
  "address", "identity", "card", "login"],
526
- default="token",
527
- help="Entry type; address/identity/card/login are structured "
528
+ default=None,
529
+ help="Entry type (default: keep the entry's type; token for a new one); "
530
+ "address/identity/card/login are structured "
528
531
  "(field payload, inject-only, never revealable to the agent)")
529
- cr_set.add_argument("--desc", default="", help="Human description shown in list/UI")
530
- cr_set.add_argument("--env-var", default="", help="Env var name used at injection (default: entry name)")
531
- cr_set.add_argument("--agent-readable", action="store_true", help="Allow the agent to reveal the decoded value into its context (default: injection-only)")
532
- cr_set.add_argument("--inject", action="store_true", help="Auto-inject into every c3_shell run")
532
+ cr_set.add_argument("--desc", default=None, help="Human description shown in list/UI (default: keep)")
533
+ cr_set.add_argument("--env-var", default=None, help="Env var name used at injection (default: keep; entry name for a new one)")
534
+ cr_set.add_argument("--agent-readable", action=argparse.BooleanOptionalAction, default=None,
535
+ help="Allow the agent to reveal the decoded value into its context (default: keep; injection-only for a new one)")
536
+ cr_set.add_argument("--inject", action=argparse.BooleanOptionalAction, default=None,
537
+ help="Auto-inject into every c3_shell run (default: keep; off for a new one)")
533
538
  cr_set.add_argument("--global", dest="use_global", action="store_true", help="Store in the global scope (~/.c3) so every C3 project can use it")
534
539
  # --path (not a trailing positional): a second positional after options
535
540
  # breaks argparse on py<3.12 ("unrecognized arguments").
@@ -578,6 +583,16 @@ def build_parser(version: str, parse_cli_ide_arg):
578
583
  cr_audit.add_argument("--json", dest="as_json", action="store_true", help="Emit raw JSON")
579
584
  cr_audit.add_argument("--path", dest="project_path", default=".", help="Project directory (default: current)")
580
585
 
586
+ cr_backup = creds_subs.add_parser(
587
+ "backup", help="Passphrase-locked copy of every value that survives an OS keychain wipe")
588
+ cr_backup.add_argument(
589
+ "backup_cmd", choices=["init", "status", "sync", "restore", "passphrase"],
590
+ help="init: turn it on (asks for a passphrase) · status · sync: copy every live "
591
+ "value now · restore: put lost values back (asks for the passphrase) · "
592
+ "passphrase: change it")
593
+ cr_backup.add_argument("--only", default="", help="restore: comma-separated names (default: all lost values)")
594
+ cr_backup.add_argument("--path", dest="project_path", default=".", help="Project directory (default: current)")
595
+
581
596
  # ── Agent Locks (docs/agent-locks.md) ───────────────────────────────
582
597
  # force-release is human-only: it bumps the fencing counter so a holder
583
598
  # that comes back is stale by construction. Agents get c3_locks instead,
@@ -125,6 +125,7 @@ _WRITE_CLASS_ALWAYS = frozenset({"Edit", "Write", "MultiEdit"})
125
125
  # Mirrors services.credential_store.VAULT_PROTECTED_FILES (parity-tested);
126
126
  # duplicated because hooks must stay import-light.
127
127
  _VAULT_FILES = frozenset({"config.json", "secrets.enc", "cred_state.json",
128
+ "vault_backup.json",
128
129
  "cred_usage.jsonl", "cred_usage.jsonl.1"})
129
130
 
130
131
  # Redirect messages per native tool
@@ -2016,7 +2016,8 @@ def api_projects_config_get():
2016
2016
  # returned by any hub route (no reveal exists here). `credentials` stays out of
2017
2017
  # _CONFIG_WRITE_SECTIONS — these dedicated routes are the only hub write path.
2018
2018
 
2019
- def _cred_entry_public(name, entry, *, usage=None, shadows_global=None):
2019
+ def _cred_entry_public(name, entry, *, usage=None, shadows_global=None,
2020
+ value_ok=None):
2020
2021
  """Explicit allowlist serializer — structurally cannot emit a value.
2021
2022
 
2022
2023
  Delegates to credential_store.public_entry so the hub, the per-project UI
@@ -2024,7 +2025,8 @@ def _cred_entry_public(name, entry, *, usage=None, shadows_global=None):
2024
2025
  is exactly the drift the write-only wire contract cannot survive."""
2025
2026
  from services import credential_store as cred_store
2026
2027
  return cred_store.public_entry(
2027
- name, entry, usage=usage, shadows_global=shadows_global)
2028
+ name, entry, usage=usage, shadows_global=shadows_global,
2029
+ value_ok=value_ok)
2028
2030
 
2029
2031
 
2030
2032
  def _resolve_cred_target(path: str, scope: str, *, mutation: bool):
@@ -2141,7 +2143,9 @@ def api_projects_credentials():
2141
2143
  entries.append(_cred_entry_public(
2142
2144
  name, entry, usage=usage,
2143
2145
  shadows_global=(entry.get("scope") == "project"
2144
- and name in global_names)))
2146
+ and name in global_names),
2147
+ value_ok=cred_store.is_resolvable(
2148
+ name, project_path=str(resolved), scope=entry["scope"])))
2145
2149
  return jsonify({"path": str(resolved), "entries": entries})
2146
2150
 
2147
2151
 
@@ -2162,29 +2166,15 @@ def api_projects_credentials_set():
2162
2166
  value = data.get("value")
2163
2167
  # Structured kinds submit a field OBJECT; the store takes JSON text.
2164
2168
  value = json.dumps(value) if isinstance(value, dict) else str(value or "")
2165
- ctype = str(data.get("type") or data.get("ctype") or "token")
2169
+ meta = cred_store.payload_meta(data)
2166
2170
  try:
2167
2171
  if value:
2168
2172
  entry = cred_store.set_credential(
2169
- name, value, scope=scope, project_path=store_path, ctype=ctype,
2170
- description=str(data.get("description") or ""),
2171
- env_var=str(data.get("env_var") or ""),
2172
- agent_readable=bool(data.get("agent_readable")),
2173
- inject=bool(data.get("inject")))
2173
+ name, value, scope=scope, project_path=store_path,
2174
+ ctype=meta.pop("type", None), **meta)
2174
2175
  else:
2175
- # Metadata-only update: touch ONLY the keys present in the payload
2176
- # so a single-field toggle can't clobber the others.
2177
- fields = {}
2178
- for key in ("description", "env_var"):
2179
- if key in data:
2180
- fields[key] = str(data[key] or "")
2181
- for key in ("agent_readable", "inject"):
2182
- if key in data:
2183
- fields[key] = bool(data[key])
2184
- if "type" in data or "ctype" in data:
2185
- fields["type"] = ctype
2186
2176
  entry = cred_store.update_metadata(
2187
- name, scope=scope, project_path=store_path, **fields)
2177
+ name, scope=scope, project_path=store_path, **meta)
2188
2178
  except cred_store.CredentialError as exc:
2189
2179
  return jsonify({"error": str(exc)}), 400
2190
2180
  except RuntimeError as exc:
@@ -2443,7 +2433,9 @@ def api_hub_credentials_overview():
2443
2433
  continue
2444
2434
  row["entries"].append(_cred_entry_public(
2445
2435
  name, entry, usage=usage,
2446
- shadows_global=name in global_entries))
2436
+ shadows_global=name in global_entries,
2437
+ value_ok=cred_store.is_resolvable(
2438
+ name, project_path=ppath, scope="project")))
2447
2439
  if name in shadowed_in:
2448
2440
  shadowed_in[name].append(
2449
2441
  {"name": row["name"], "path": ppath})
@@ -2452,11 +2444,27 @@ def api_hub_credentials_overview():
2452
2444
  projects_out.append(row)
2453
2445
  global_usage = cred_store.read_usage_state(str(home)) if home else {}
2454
2446
  global_out = [
2455
- {**_cred_entry_public(name, entry, usage=global_usage),
2447
+ {**_cred_entry_public(
2448
+ name, entry, usage=global_usage,
2449
+ value_ok=cred_store.is_resolvable(
2450
+ name, project_path=str(home), scope="global")),
2456
2451
  "shadowed_in": shadowed_in.get(name, [])}
2457
2452
  for name, entry in global_entries.items()
2458
2453
  ]
2459
- return jsonify({"global": {"entries": global_out}, "projects": projects_out})
2454
+ return jsonify({"global": {"entries": global_out}, "projects": projects_out,
2455
+ "backup": _cred_backup_summary(
2456
+ [row["path"] for row in projects_out if row["initialized"]])})
2457
+
2458
+
2459
+ def _cred_backup_summary(project_paths) -> dict:
2460
+ """Backup state as counts for the Hub banner; a broken file reports its error."""
2461
+ from services import credential_backup
2462
+ try:
2463
+ st = credential_backup.status(project_paths)
2464
+ except credential_backup.BackupError as exc:
2465
+ return {"enabled": True, "error": str(exc), "restorable": 0, "lost": 0}
2466
+ return {"enabled": st["enabled"], "restorable": len(st["restorable"]),
2467
+ "lost": len(st["lost"]), "not_backed_up": len(st["not_backed_up"])}
2460
2468
 
2461
2469
 
2462
2470
  #: Bulk actions may only ever REDUCE what a credential is exposed to.
@@ -1197,6 +1197,11 @@ function CredRow({ entry, striped, owner, onOpen, onMenu, check,
1197
1197
  <div style={{ display: 'flex', alignItems: 'center', flexWrap: 'wrap', gap: 7 }}>
1198
1198
  <span className="mono" style={{ fontWeight: 600, color: T.text, fontSize: 12.5 }}>{entry.name}</span>
1199
1199
  <Badge color={entry.scope === 'global' ? T.accent : T.blue}>{entry.scope}</Badge>
1200
+ {!!entry.value_missing && (
1201
+ <span title="Registered, but the OS keychain no longer holds its value — injecting it fails. Replace the secret to restore it.">
1202
+ <Badge color={T.error}>value missing</Badge>
1203
+ </span>
1204
+ )}
1200
1205
  {!!entry.shadows_global && (
1201
1206
  <span title="This project's value wins over the global entry of the same name">
1202
1207
  <Badge color={T.warn}>overrides global</Badge>
@@ -2074,6 +2079,7 @@ function CredSearchResults({ groups, total, selected, setSelected, onOpen, onMen
2074
2079
  minWidth: 150, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap',
2075
2080
  }}>{def.projectName}</span>
2076
2081
  <Badge color={e.scope === 'global' ? T.accent : T.blue}>{e.scope}</Badge>
2082
+ {!!e.value_missing && <Badge color={T.error}>value missing</Badge>}
2077
2083
  {!!e.shadows_global && <Badge color={T.warn}>overrides global</Badge>}
2078
2084
  <span className="mono" style={{ fontSize: 11, color: T.textDim }}>
2079
2085
  {e.type || 'token'} · ••••{e.value_len}
@@ -2287,6 +2293,18 @@ function HubCredentials({ projects, onOpenDrill }) {
2287
2293
  const totalProjEntries = ((ov || {}).projects || []).reduce((n, r) => n + (r.entries || []).length, 0);
2288
2294
  const globalCount = ((((ov || {}).global) || {}).entries || []).length;
2289
2295
 
2296
+ // Restore and init read a passphrase from the keyboard, so they stay
2297
+ // terminal commands; the Hub only says which one is needed.
2298
+ const bk = (ov || {}).backup;
2299
+ const backupNote = !bk ? null
2300
+ : bk.restorable > 0 ? { tone: T.error, cmd: 'c3 creds backup restore',
2301
+ text: `${bk.restorable} credential${bk.restorable === 1 ? '' : 's'} lost ${bk.restorable === 1 ? 'its value' : 'their values'} in the OS keychain and can be restored from the vault backup.` }
2302
+ : bk.lost > 0 ? { tone: T.error, cmd: '',
2303
+ text: `${bk.lost} credential${bk.lost === 1 ? ' has' : 's have'} no stored value and no backup copy — replace each secret marked "value missing".` }
2304
+ : !bk.enabled ? { tone: T.warn, cmd: 'c3 creds backup init',
2305
+ text: 'No vault backup: values live only in the OS keychain, which Windows can empty on a restart.' }
2306
+ : null;
2307
+
2290
2308
  return (
2291
2309
  <div className="fade-up" style={{ maxWidth: 1100 }}>
2292
2310
  <div style={{ display: 'flex', alignItems: 'center', gap: 10, marginBottom: 10 }}>
@@ -2308,6 +2326,20 @@ function HubCredentials({ projects, onOpenDrill }) {
2308
2326
  }}><I name="refresh" size={12} /> Refresh</button>
2309
2327
  </div>
2310
2328
 
2329
+ {backupNote && (
2330
+ <div style={{
2331
+ display: 'flex', alignItems: 'center', gap: 10, flexWrap: 'wrap',
2332
+ marginBottom: 10, padding: '8px 12px', fontSize: 12, color: T.text,
2333
+ border: `1px solid ${T.border}`, borderLeft: `3px solid ${backupNote.tone}`,
2334
+ borderRadius: 6, background: T.surfaceAlt,
2335
+ }}>
2336
+ <span>{backupNote.text}</span>
2337
+ {backupNote.cmd && (
2338
+ <span>In a terminal: <span className="mono" style={{ color: backupNote.tone }}>{backupNote.cmd}</span></span>
2339
+ )}
2340
+ </div>
2341
+ )}
2342
+
2311
2343
  {/* Cross-project search — always visible, above the sub-tabs */}
2312
2344
  <div style={{ display: 'flex', alignItems: 'center', gap: 8, marginBottom: 8, flexWrap: 'wrap' }}>
2313
2345
  <div style={{
@@ -2766,7 +2766,10 @@ def api_credentials_list():
2766
2766
  usage = cred_store.read_usage_state(pp)
2767
2767
  out = []
2768
2768
  for name, entry in cred_store.list_entries(pp).items():
2769
- out.append(cred_store.public_entry(name, entry, usage=usage))
2769
+ out.append(cred_store.public_entry(
2770
+ name, entry, usage=usage,
2771
+ value_ok=cred_store.is_resolvable(
2772
+ name, project_path=pp, scope=entry["scope"])))
2770
2773
  return jsonify({"entries": out})
2771
2774
 
2772
2775
 
@@ -2781,32 +2784,15 @@ def api_credentials_set():
2781
2784
  value = data.get("value")
2782
2785
  # Structured kinds submit a field OBJECT; the store takes JSON text.
2783
2786
  value = json.dumps(value) if isinstance(value, dict) else str(value or "")
2784
- ctype = str(data.get("type") or data.get("ctype") or "token")
2785
- meta = {
2786
- "description": str(data.get("description") or ""),
2787
- "env_var": str(data.get("env_var") or ""),
2788
- "agent_readable": bool(data.get("agent_readable")),
2789
- "inject": bool(data.get("inject")),
2790
- }
2787
+ meta = cred_store.payload_meta(data)
2791
2788
  try:
2792
2789
  if value:
2793
2790
  entry = cred_store.set_credential(
2794
2791
  name, value, scope=scope, project_path=str(PROJECT_PATH),
2795
- ctype=ctype, **meta)
2792
+ ctype=meta.pop("type", None), **meta)
2796
2793
  else:
2797
- # Metadata-only update: touch ONLY the keys present in the payload
2798
- # so a single-field toggle can't clobber the others.
2799
- fields = {}
2800
- for key in ("description", "env_var"):
2801
- if key in data:
2802
- fields[key] = str(data[key] or "")
2803
- for key in ("agent_readable", "inject"):
2804
- if key in data:
2805
- fields[key] = bool(data[key])
2806
- if "type" in data or "ctype" in data:
2807
- fields["type"] = ctype
2808
2794
  entry = cred_store.update_metadata(
2809
- name, scope=scope, project_path=str(PROJECT_PATH), **fields)
2795
+ name, scope=scope, project_path=str(PROJECT_PATH), **meta)
2810
2796
  except cred_store.CredentialError as exc:
2811
2797
  return jsonify({"error": str(exc)}), 400
2812
2798
  except RuntimeError as exc:
@@ -64,7 +64,8 @@ def _log_access(svc, action: str, name: str, scope: str, response: str) -> None:
64
64
  pass
65
65
 
66
66
 
67
- def _format_entry_line(name: str, entry: dict, usage: dict) -> str:
67
+ def _format_entry_line(name: str, entry: dict, usage: dict,
68
+ missing: bool = False) -> str:
68
69
  flags = []
69
70
  if entry.get("inject"):
70
71
  flags.append("inject")
@@ -73,7 +74,7 @@ def _format_entry_line(name: str, entry: dict, usage: dict) -> str:
73
74
  last_used = (usage.get(name) or {}).get("last_used", "")
74
75
  parts = [
75
76
  f"{name} [{entry.get('scope', '?')}/{entry.get('type', 'token')}]",
76
- f"len={entry.get('value_len', '?')}",
77
+ "VALUE MISSING" if missing else f"len={entry.get('value_len', '?')}",
77
78
  ]
78
79
  display = entry.get("display") or {}
79
80
  if display:
@@ -97,8 +98,22 @@ def _act_list(project_path: str) -> str:
97
98
  "The user manages them via the Credentials UI tab or `c3 creds set`."
98
99
  )
99
100
  usage = cs.read_usage_state(project_path)
101
+ missing = {n for n, e in entries.items() if not cs.is_resolvable(
102
+ n, project_path=project_path, scope=e["scope"])}
100
103
  lines = [f"[creds] {len(entries)} entries (project scope shadows global):"]
101
- lines += [_format_entry_line(n, e, usage) for n, e in entries.items()]
104
+ lines += [_format_entry_line(n, e, usage, n in missing)
105
+ for n, e in entries.items()]
106
+ if missing:
107
+ from services import credential_backup
108
+ way_back = ("The user restores them in a terminal with `c3 creds backup "
109
+ "restore` (it asks for the backup passphrase)"
110
+ if credential_backup.is_enabled() else
111
+ "No vault backup is configured; the user re-enters them "
112
+ "(Credentials UI or `c3 creds set`)")
113
+ lines.append(
114
+ f"[creds:value-missing] {len(missing)} registered entries have no "
115
+ "stored value (the OS keychain no longer holds it); injecting them "
116
+ f"fails. {way_back}.")
102
117
  lines.append(_USAGE_FOOTER)
103
118
  return "\n".join(lines)
104
119
 
@@ -384,15 +399,17 @@ def handle_credentials(action: str, svc, finalize, **kwargs) -> str:
384
399
  "(Credentials UI or `c3 creds set --agent-readable`)."
385
400
  )
386
401
  else:
402
+ # Empty/false arguments mean "not given": the entry keeps
403
+ # its current settings rather than resetting to defaults.
387
404
  entry = cs.set_credential(
388
405
  name, value,
389
406
  scope=scope,
390
407
  project_path=project_path,
391
- description=kwargs.get("description") or "",
392
- ctype=kwargs.get("ctype") or "token",
393
- env_var=kwargs.get("env_var") or "",
394
- agent_readable=want_readable,
395
- inject=bool(kwargs.get("inject")),
408
+ description=kwargs.get("description") or None,
409
+ ctype=kwargs.get("ctype") or None,
410
+ env_var=kwargs.get("env_var") or None,
411
+ agent_readable=True if want_readable else None,
412
+ inject=True if kwargs.get("inject") else None,
396
413
  )
397
414
  resp = (
398
415
  f"[creds:set] {name} (scope={scope}, "
@@ -753,6 +753,7 @@ const CredentialsPanel = () => {
753
753
  {entry.name}
754
754
  </span>
755
755
  <Badge color={entry.scope === "global" ? T.accent : T.blue}>{entry.scope}</Badge>
756
+ {!!entry.value_missing && <Badge color={T.error}>value missing</Badge>}
756
757
  <Badge color={T.textMuted}>{entry.type || "token"}</Badge>
757
758
  {CREDS_STRUCTURED[entry.type] ? (
758
759
  <span className="mono" style={{ color: T.text }}>
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: code-context-control
3
- Version: 2.143.0
3
+ Version: 2.145.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
@@ -44,6 +44,7 @@ Requires-Dist: rich>=13.0.0
44
44
  Requires-Dist: click>=8.0.0
45
45
  Requires-Dist: pyyaml>=6.0.0
46
46
  Requires-Dist: keyring>=24.0
47
+ Requires-Dist: cryptography>=41.0
47
48
  Provides-Extra: vector
48
49
  Requires-Dist: scikit-learn>=1.3.0; extra == "vector"
49
50
  Requires-Dist: numpy>=1.24.0; extra == "vector"
@@ -226,6 +226,7 @@ services/context_snapshot.py
226
226
  services/conversation_store.py
227
227
  services/cred_audit.py
228
228
  services/cred_telemetry.py
229
+ services/credential_backup.py
229
230
  services/credential_store.py
230
231
  services/delegate_agents.py
231
232
  services/delegate_hints.py
@@ -362,6 +363,7 @@ tests/test_confirm_guard_wiring.py
362
363
  tests/test_cooccurrence_bounds.py
363
364
  tests/test_cred_audit.py
364
365
  tests/test_cred_telemetry.py
366
+ tests/test_credential_backup.py
365
367
  tests/test_credential_login_kind.py
366
368
  tests/test_credential_store.py
367
369
  tests/test_credential_ui_parity.py
@@ -18,6 +18,7 @@ rich>=13.0.0
18
18
  click>=8.0.0
19
19
  pyyaml>=6.0.0
20
20
  keyring>=24.0
21
+ cryptography>=41.0
21
22
 
22
23
  [dev]
23
24
  pytest>=7.0.0
@@ -1571,26 +1571,18 @@ def mobile_credentials_set():
1571
1571
  "needs_confirmation": True, "confirm_with": name,
1572
1572
  }), 400
1573
1573
 
1574
+ meta = cred_store.payload_meta(data)
1574
1575
  try:
1575
1576
  if value:
1577
+ # ctype stays explicit here: "keep the existing type" would let a
1578
+ # phone write field JSON into a structured entry.
1579
+ meta.pop("type", None)
1576
1580
  entry = cred_store.set_credential(
1577
- name, value, scope=scope, project_path=store_path, ctype=ctype,
1578
- description=str(data.get("description") or ""),
1579
- env_var=str(data.get("env_var") or ""),
1580
- agent_readable=wants_readable,
1581
- inject=bool(data.get("inject")))
1581
+ name, value, scope=scope, project_path=store_path,
1582
+ ctype=ctype, **meta)
1582
1583
  else:
1583
- fields = {}
1584
- for key in ("description", "env_var"):
1585
- if key in data:
1586
- fields[key] = str(data[key] or "")
1587
- for key in ("agent_readable", "inject"):
1588
- if key in data:
1589
- fields[key] = bool(data[key])
1590
- if "type" in data or "ctype" in data:
1591
- fields["type"] = ctype
1592
1584
  entry = cred_store.update_metadata(
1593
- name, scope=scope, project_path=store_path, **fields)
1585
+ name, scope=scope, project_path=store_path, **meta)
1594
1586
  except cred_store.CredentialError as exc:
1595
1587
  return jsonify({"error": str(exc)}), 400
1596
1588
  except (ValueError, RuntimeError) as exc: