cc-session-tools 2.3.0__tar.gz → 2.5.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 (242) hide show
  1. {cc_session_tools-2.3.0/src/cc_session_tools.egg-info → cc_session_tools-2.5.0}/PKG-INFO +76 -14
  2. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/README.md +75 -13
  3. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/pyproject.toml +1 -1
  4. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/src/cc_session_tools/cli/ccst.py +165 -54
  5. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/src/cc_session_tools/lib/doctor.py +111 -9
  6. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/src/cc_session_tools/lib/doctor_mutes.py +12 -1
  7. cc_session_tools-2.5.0/src/cc_session_tools/lib/install_sync.py +369 -0
  8. cc_session_tools-2.5.0/src/cc_session_tools/lib/proc_lock.py +112 -0
  9. cc_session_tools-2.5.0/src/cc_session_tools/lib/scheduler/lock.py +40 -0
  10. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/src/cc_session_tools/lib/sessions_db.py +6 -0
  11. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0/src/cc_session_tools.egg-info}/PKG-INFO +76 -14
  12. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/src/cc_session_tools.egg-info/SOURCES.txt +5 -0
  13. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/src/cccs_hooks/bash_security_review.py +43 -37
  14. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/src/cccs_hooks/normalise.py +4 -0
  15. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/tests/test_bash_security_review.py +222 -0
  16. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/tests/test_ccst_doctor.py +239 -0
  17. cc_session_tools-2.5.0/tests/test_ccst_install_everything.py +375 -0
  18. cc_session_tools-2.5.0/tests/test_ccst_main_gate.py +160 -0
  19. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/tests/test_ccst_repair_sessions_cli.py +39 -0
  20. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/tests/test_doctor_mutes.py +13 -0
  21. cc_session_tools-2.5.0/tests/test_install_sync.py +522 -0
  22. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/tests/test_normalise.py +34 -0
  23. cc_session_tools-2.5.0/tests/test_proc_lock.py +96 -0
  24. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/tests/test_sessions_db.py +2 -2
  25. cc_session_tools-2.3.0/src/cc_session_tools/lib/scheduler/lock.py +0 -104
  26. cc_session_tools-2.3.0/tests/test_ccst_install_everything.py +0 -160
  27. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/LICENSE +0 -0
  28. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/setup.cfg +0 -0
  29. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/src/cc_session_tools/__init__.py +0 -0
  30. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/src/cc_session_tools/cli/__init__.py +0 -0
  31. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/src/cc_session_tools/cli/ccd.py +0 -0
  32. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/src/cc_session_tools/cli/ccmsg.py +0 -0
  33. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/src/cc_session_tools/cli/ccr.py +0 -0
  34. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/src/cc_session_tools/cli/ccs.py +0 -0
  35. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/src/cc_session_tools/cli/ccsched.py +0 -0
  36. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/src/cc_session_tools/cli/migrate_ccmsg.py +0 -0
  37. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/src/cc_session_tools/cli/migrate_ccsched.py +0 -0
  38. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/src/cc_session_tools/cli/migrate_sessions_db.py +0 -0
  39. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/src/cc_session_tools/cli/migrate_telemetry.py +0 -0
  40. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/src/cc_session_tools/config/hooks-bundle.json +0 -0
  41. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/src/cc_session_tools/config/session-tag-hook.json +0 -0
  42. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/src/cc_session_tools/hooks_install.py +0 -0
  43. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/src/cc_session_tools/lib/__init__.py +0 -0
  44. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/src/cc_session_tools/lib/claude_flags.py +0 -0
  45. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/src/cc_session_tools/lib/claude_md_install.py +0 -0
  46. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/src/cc_session_tools/lib/db.py +0 -0
  47. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/src/cc_session_tools/lib/debug.py +0 -0
  48. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/src/cc_session_tools/lib/hook_registry.py +0 -0
  49. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/src/cc_session_tools/lib/levenshtein.py +0 -0
  50. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/src/cc_session_tools/lib/messaging/__init__.py +0 -0
  51. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/src/cc_session_tools/lib/messaging/addressing.py +0 -0
  52. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/src/cc_session_tools/lib/messaging/cursor.py +0 -0
  53. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/src/cc_session_tools/lib/messaging/lock.py +0 -0
  54. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/src/cc_session_tools/lib/messaging/message.py +0 -0
  55. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/src/cc_session_tools/lib/messaging/move_safety.py +0 -0
  56. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/src/cc_session_tools/lib/messaging/repository.py +0 -0
  57. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/src/cc_session_tools/lib/messaging/retention.py +0 -0
  58. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/src/cc_session_tools/lib/messaging/service.py +0 -0
  59. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/src/cc_session_tools/lib/messaging/store.py +0 -0
  60. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/src/cc_session_tools/lib/paths.py +0 -0
  61. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/src/cc_session_tools/lib/pdata/__init__.py +0 -0
  62. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/src/cc_session_tools/lib/pdata/backup.py +0 -0
  63. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/src/cc_session_tools/lib/pdata/classify.py +0 -0
  64. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/src/cc_session_tools/lib/pdata/cutover.py +0 -0
  65. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/src/cc_session_tools/lib/pdata/formatting.py +0 -0
  66. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/src/cc_session_tools/lib/pdata/importers.py +0 -0
  67. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/src/cc_session_tools/lib/pdata/init_paths.py +0 -0
  68. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/src/cc_session_tools/lib/pdata/init_service.py +0 -0
  69. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/src/cc_session_tools/lib/pdata/manifest.py +0 -0
  70. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/src/cc_session_tools/lib/pdata/naming.py +0 -0
  71. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/src/cc_session_tools/lib/pdata/repository.py +0 -0
  72. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/src/cc_session_tools/lib/pdata/service.py +0 -0
  73. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/src/cc_session_tools/lib/pdata/session_output.py +0 -0
  74. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/src/cc_session_tools/lib/pdata/store.py +0 -0
  75. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/src/cc_session_tools/lib/pdata/verify.py +0 -0
  76. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/src/cc_session_tools/lib/picker.py +0 -0
  77. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/src/cc_session_tools/lib/prompts.py +0 -0
  78. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/src/cc_session_tools/lib/roots.py +0 -0
  79. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/src/cc_session_tools/lib/rules.py +0 -0
  80. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/src/cc_session_tools/lib/scheduler/__init__.py +0 -0
  81. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/src/cc_session_tools/lib/scheduler/bundled_jobs.py +0 -0
  82. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/src/cc_session_tools/lib/scheduler/cadence.py +0 -0
  83. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/src/cc_session_tools/lib/scheduler/cursor.py +0 -0
  84. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/src/cc_session_tools/lib/scheduler/digest.py +0 -0
  85. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/src/cc_session_tools/lib/scheduler/due.py +0 -0
  86. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/src/cc_session_tools/lib/scheduler/duration.py +0 -0
  87. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/src/cc_session_tools/lib/scheduler/jobspec.py +0 -0
  88. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/src/cc_session_tools/lib/scheduler/ledger.py +0 -0
  89. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/src/cc_session_tools/lib/scheduler/notify.py +0 -0
  90. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/src/cc_session_tools/lib/scheduler/reconcile.py +0 -0
  91. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/src/cc_session_tools/lib/scheduler/registry.py +0 -0
  92. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/src/cc_session_tools/lib/scheduler/runner.py +0 -0
  93. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/src/cc_session_tools/lib/scheduler/state.py +0 -0
  94. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/src/cc_session_tools/lib/scheduler/store.py +0 -0
  95. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/src/cc_session_tools/lib/scheduler/surface.py +0 -0
  96. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/src/cc_session_tools/lib/scheduler/throttle.py +0 -0
  97. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/src/cc_session_tools/lib/scheduler/worker.py +0 -0
  98. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/src/cc_session_tools/lib/session_gc.py +0 -0
  99. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/src/cc_session_tools/lib/sessions.py +0 -0
  100. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/src/cc_session_tools/lib/sessions_repair.py +0 -0
  101. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/src/cc_session_tools/lib/shell_install.py +0 -0
  102. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/src/cc_session_tools/lib/tasklist.py +0 -0
  103. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/src/cc_session_tools/lib/telemetry_store.py +0 -0
  104. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/src/cc_session_tools/skills/analyse-cc-usage/SKILL.md +0 -0
  105. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/src/cc_session_tools/skills/delete-sessions/SKILL.md +0 -0
  106. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/src/cc_session_tools/skills/delete-sessions/scripts/delete_sessions.py +0 -0
  107. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/src/cc_session_tools/skills/do-executor-critic-assessor-loop/SKILL.md +0 -0
  108. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/src/cc_session_tools/skills/find-claude-code-session/SKILL.md +0 -0
  109. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/src/cc_session_tools/skills/generate-8digit-code/SKILL.md +0 -0
  110. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/src/cc_session_tools/skills/generate-8digit-code/scripts/generate_8digit_code.py +0 -0
  111. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/src/cc_session_tools/skills/list-empty-sessions/SKILL.md +0 -0
  112. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/src/cc_session_tools/skills/list-empty-sessions/scripts/list_empty_sessions.py +0 -0
  113. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/src/cc_session_tools/skills/manage-recurring-cc-jobs-using-ccsched/SKILL.md +0 -0
  114. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/src/cc_session_tools/skills/move-session/SKILL.md +0 -0
  115. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/src/cc_session_tools/skills/move-session/hooks/sessionstart-pending-rename.sh +0 -0
  116. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/src/cc_session_tools/skills/move-session/scripts/cc_session_rules.py +0 -0
  117. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/src/cc_session_tools/skills/move-session/scripts/move_session.py +0 -0
  118. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/src/cc_session_tools/skills/pm-pdata-conflict-resolution/SKILL.md +0 -0
  119. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/src/cc_session_tools/skills/pm-pdata-schema-design/SKILL.md +0 -0
  120. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/src/cc_session_tools/skills/pm-project-init/SKILL.md +0 -0
  121. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/src/cc_session_tools/skills/pm-update-central-files/SKILL.md +0 -0
  122. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/src/cc_session_tools/skills/reduce-persistent-context/CALIBRATION.md +0 -0
  123. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/src/cc_session_tools/skills/reduce-persistent-context/SKILL.md +0 -0
  124. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/src/cc_session_tools/skills/reduce-persistent-context/scripts/analyze_context.py +0 -0
  125. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/src/cc_session_tools/skills/reduce-persistent-context/scripts/duplicates.py +0 -0
  126. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/src/cc_session_tools/skills/reduce-persistent-context/scripts/measure.py +0 -0
  127. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/src/cc_session_tools/skills/reduce-persistent-context/scripts/report.py +0 -0
  128. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/src/cc_session_tools/skills/reduce-persistent-context/scripts/tokens.py +0 -0
  129. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/src/cc_session_tools/skills/reduce-persistent-context/scripts/usage.py +0 -0
  130. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/src/cc_session_tools/skills/select-agent-model/SKILL.md +0 -0
  131. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/src/cc_session_tools/skills/send-session-message/SKILL.md +0 -0
  132. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/src/cc_session_tools/skills/update-command-cache/SKILL.md +0 -0
  133. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/src/cc_session_tools/skills/update-command-cache/scripts/update_command_cache.py +0 -0
  134. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/src/cc_session_tools.egg-info/dependency_links.txt +0 -0
  135. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/src/cc_session_tools.egg-info/entry_points.txt +0 -0
  136. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/src/cc_session_tools.egg-info/requires.txt +0 -0
  137. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/src/cc_session_tools.egg-info/top_level.txt +0 -0
  138. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/src/cccs_hooks/__init__.py +0 -0
  139. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/src/cccs_hooks/after_response.py +0 -0
  140. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/src/cccs_hooks/bash_hard_deny.py +0 -0
  141. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/src/cccs_hooks/cache.py +0 -0
  142. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/src/cccs_hooks/catchup.py +0 -0
  143. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/src/cccs_hooks/confirm_8digit.py +0 -0
  144. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/src/cccs_hooks/last_screenshot.py +0 -0
  145. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/src/cccs_hooks/marker_allow.py +0 -0
  146. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/src/cccs_hooks/markers.py +0 -0
  147. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/src/cccs_hooks/messaging_deliver.py +0 -0
  148. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/src/cccs_hooks/pending_migration.py +0 -0
  149. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/src/cccs_hooks/session_tag.py +0 -0
  150. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/src/cccs_hooks/stats.py +0 -0
  151. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/src/cccs_hooks/telemetry.py +0 -0
  152. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/src/cccs_hooks/telemetry_query.py +0 -0
  153. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/src/cccs_hooks/telemetry_trim.py +0 -0
  154. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/src/cccs_hooks/transcript.py +0 -0
  155. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/src/cccs_hooks/worklog_guard.py +0 -0
  156. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/src/claude_code_usage/__init__.py +0 -0
  157. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/src/claude_code_usage/attribution.py +0 -0
  158. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/src/claude_code_usage/cache.py +0 -0
  159. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/src/claude_code_usage/ccusage_wrapper.py +0 -0
  160. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/src/claude_code_usage/cli.py +0 -0
  161. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/src/claude_code_usage/data/pricing.json +0 -0
  162. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/src/claude_code_usage/parent_inference.py +0 -0
  163. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/src/claude_code_usage/parser.py +0 -0
  164. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/src/claude_code_usage/pricing.py +0 -0
  165. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/src/claude_code_usage/query.py +0 -0
  166. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/src/claude_code_usage/report.py +0 -0
  167. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/src/claude_code_usage/schema.py +0 -0
  168. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/src/claude_code_usage/session_names.py +0 -0
  169. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/tests/test_after_response.py +0 -0
  170. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/tests/test_attribution.py +0 -0
  171. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/tests/test_bash_hard_deny.py +0 -0
  172. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/tests/test_cache.py +0 -0
  173. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/tests/test_cache_sqlite.py +0 -0
  174. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/tests/test_ccr_orphans.py +0 -0
  175. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/tests/test_ccs_emptiness.py +0 -0
  176. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/tests/test_ccs_eta.py +0 -0
  177. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/tests/test_ccs_list_mode.py +0 -0
  178. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/tests/test_ccs_scope_flags.py +0 -0
  179. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/tests/test_ccs_sentinel_sort.py +0 -0
  180. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/tests/test_ccs_session_counts.py +0 -0
  181. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/tests/test_ccst_bundle_discovery.py +0 -0
  182. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/tests/test_ccst_ccsched_jobs_cli.py +0 -0
  183. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/tests/test_ccst_cli.py +0 -0
  184. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/tests/test_ccst_gc_report.py +0 -0
  185. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/tests/test_ccst_hook_dispatcher.py +0 -0
  186. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/tests/test_ccst_hooks_install_prune.py +0 -0
  187. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/tests/test_ccst_hooks_install_zero_arg.py +0 -0
  188. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/tests/test_ccst_hooks_uninstall.py +0 -0
  189. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/tests/test_ccst_pdata_cli.py +0 -0
  190. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/tests/test_ccst_pdata_init_cli.py +0 -0
  191. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/tests/test_ccst_pdata_reconcile_cli.py +0 -0
  192. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/tests/test_ccst_pdata_verify_cli.py +0 -0
  193. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/tests/test_ccst_sessions_cli.py +0 -0
  194. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/tests/test_ccst_shell_install.py +0 -0
  195. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/tests/test_ccst_skills_install.py +0 -0
  196. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/tests/test_ccst_skills_uninstall.py +0 -0
  197. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/tests/test_ccst_telemetry_query.py +0 -0
  198. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/tests/test_ccst_telemetry_trim.py +0 -0
  199. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/tests/test_ccusage_wrapper.py +0 -0
  200. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/tests/test_claude_flags.py +0 -0
  201. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/tests/test_claude_md_install.py +0 -0
  202. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/tests/test_cli.py +0 -0
  203. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/tests/test_cli_ccd.py +0 -0
  204. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/tests/test_cli_ccd_dry_run.py +0 -0
  205. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/tests/test_cli_ccr.py +0 -0
  206. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/tests/test_cli_ccs.py +0 -0
  207. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/tests/test_cli_version.py +0 -0
  208. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/tests/test_confirm_8digit.py +0 -0
  209. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/tests/test_db.py +0 -0
  210. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/tests/test_debug.py +0 -0
  211. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/tests/test_empty_session.py +0 -0
  212. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/tests/test_hook_cache.py +0 -0
  213. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/tests/test_hooks_install.py +0 -0
  214. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/tests/test_last_screenshot.py +0 -0
  215. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/tests/test_levenshtein.py +0 -0
  216. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/tests/test_marker_allow.py +0 -0
  217. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/tests/test_migrate_ccmsg.py +0 -0
  218. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/tests/test_migrate_ccsched.py +0 -0
  219. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/tests/test_migrate_sessions_db.py +0 -0
  220. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/tests/test_migrate_telemetry.py +0 -0
  221. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/tests/test_parent_inference.py +0 -0
  222. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/tests/test_parser.py +0 -0
  223. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/tests/test_paths.py +0 -0
  224. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/tests/test_pending_migration_hook.py +0 -0
  225. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/tests/test_picker.py +0 -0
  226. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/tests/test_pricing.py +0 -0
  227. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/tests/test_prompts.py +0 -0
  228. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/tests/test_query.py +0 -0
  229. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/tests/test_report.py +0 -0
  230. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/tests/test_roots.py +0 -0
  231. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/tests/test_rules.py +0 -0
  232. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/tests/test_scheduler_bundled_jobs.py +0 -0
  233. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/tests/test_schema.py +0 -0
  234. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/tests/test_session_names.py +0 -0
  235. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/tests/test_session_tag.py +0 -0
  236. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/tests/test_sessions.py +0 -0
  237. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/tests/test_sessions_repair.py +0 -0
  238. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/tests/test_tasklist.py +0 -0
  239. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/tests/test_telemetry.py +0 -0
  240. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/tests/test_telemetry_store.py +0 -0
  241. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/tests/test_transcript.py +0 -0
  242. {cc_session_tools-2.3.0 → cc_session_tools-2.5.0}/tests/test_worklog_guard.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cc-session-tools
3
- Version: 2.3.0
3
+ Version: 2.5.0
4
4
  Summary: Claude Code session management CLI tools (ccd, ccr, ccs, claude-code-usage, ccst) and hook library (cccs_hooks)
5
5
  Author: raffishquartan
6
6
  License: MIT License
@@ -142,7 +142,16 @@ It runs `ccst doctor` at the end so you can see the health check immediately. Re
142
142
  > **Options:** `--from-source` reinstalls from the local clone rather than
143
143
  > PyPI. `--upgrade` forces an upgrade of an existing install.
144
144
 
145
- > **Note:** `install-everything.sh` handles steps 1–5 of setup. Step 6 — adding broader CCST guidance to your global `~/.claude/CLAUDE.md` (session management, 8-digit gate, etc.) — is interactive and must be run separately afterwards. See [Configure your global CLAUDE.md](#configure-your-global-claudemd) below.
145
+ > **Note:** `install-everything.sh` does everything except one interactive step — adding broader
146
+ > CCST guidance to your global `~/.claude/CLAUDE.md` (session management, 8-digit gate, etc.),
147
+ > which must be run separately afterwards. See [Configure your global
148
+ > CLAUDE.md](#configure-your-global-claudemd) below.
149
+
150
+ > **After upgrading** (`uv tool install --reinstall`/`--upgrade`, or `pip`/`pipx` equivalents):
151
+ > nothing to do. The next `ccst` command notices that the installed version doesn't match the
152
+ > version your config was last synced to, runs `install-everything --apply` itself, and tells you
153
+ > on stderr that it did. See [Automatic install sync](#automatic-install-sync) below for the exempt
154
+ > commands, the `CCST_NO_AUTO_SYNC=1` escape hatch, and what happens when the sync fails.
146
155
 
147
156
  **Manual path — step by step:**
148
157
 
@@ -151,11 +160,9 @@ It runs `ccst doctor` at the end so you can see the health check immediately. Re
151
160
  uv tool install cc-session-tools # recommended
152
161
  # pipx install cc-session-tools # alternative
153
162
 
154
- # 2. Install bundled skills, hooks, and the ccl shell function (each command is
155
- # idempotent — safe to re-run after upgrades)
156
- ccst skills install --apply # symlinks skills into ~/.claude/skills/
157
- ccst hooks install --apply # merges all bundled hooks into ~/.claude/settings.json
158
- ccst shell install --apply # writes ccl() to ~/.shellrc.d/ccl.sh
163
+ # 2. Install bundled skills, hooks, the ccl shell function, the CLAUDE.md
164
+ # messaging block and the scheduled jobs (idempotent — safe to re-run)
165
+ ccst install-everything --apply
159
166
 
160
167
  # 3. Verify everything is wired up
161
168
  ccst doctor
@@ -195,10 +202,8 @@ shell (or re-source your rc file) to activate `ccl`.
195
202
  uv tool upgrade cc-session-tools # recommended
196
203
  # pipx upgrade cc-session-tools # alternative
197
204
 
198
- # 2. Pick up any new bundled skills, hooks, and shell helpers
199
- ccst skills install --apply
200
- ccst hooks install --apply
201
- ccst shell install --apply
205
+ # 2. Optional — the next ccst command does this for you automatically
206
+ ccst install-everything --apply
202
207
 
203
208
  # 3. Verify
204
209
  ccst doctor
@@ -213,6 +218,40 @@ source ~/.bashrc # bash
213
218
  source ~/.zshrc # zsh
214
219
  ```
215
220
 
221
+ ### Automatic install sync
222
+
223
+ `uv`, `pip` and `pipx` run no code after unpacking a wheel, so nothing at install time can wire a
224
+ newly-added skill or hook into `~/.claude`. Code is fine — skills symlinks and `ccst hooks run`
225
+ resolve into the tools path the installer reuses in place — but *registration* isn't: a hook added
226
+ in a newer version isn't in `settings.json` until `install-everything` runs, so it silently never
227
+ fires.
228
+
229
+ `ccst` closes that gap itself. Before dispatching any command, it compares the installed version
230
+ against the version your config was last synced to. On a mismatch it runs the five install steps
231
+ (skills, hooks, shell, CLAUDE.md, scheduled jobs), prints two lines to **stderr**, and then runs
232
+ the command you actually asked for:
233
+
234
+ ```
235
+ ccst: install config is out of sync (installed 2.5.0, last synced 2.4.0) — syncing…
236
+ ccst: install config synced to 2.5.0.
237
+ ```
238
+
239
+ - **Nothing is written to stdout**, so `--json` output and scripted callers are unaffected, and
240
+ **your command's exit code is never changed** by the sync.
241
+ - **Exempt commands** (never trigger a sync): `ccst hooks run <verb>` (fires on every tool call in
242
+ every open Claude Code session), `install-everything`, `doctor`, `repair`, `migrate`, and any
243
+ `install`/`uninstall` verb — those are you driving install state by hand, possibly with your own
244
+ `--target`, and a default-target sync underneath them would be self-contradictory.
245
+ - **`CCST_NO_AUTO_SYNC=1`** disables it entirely, for CI, bisecting, or any environment where
246
+ `~/.claude` must not be touched.
247
+ - **If a sync fails** (for example `~/.claude/skills/<name>` exists as a real directory rather than
248
+ a symlink), the full step output is printed to stderr, the failure is remembered, and it backs
249
+ off for six hours rather than retrying on every command — printing one warning line each time
250
+ instead. `ccst doctor` reports that state as a **FAIL**, since it will not recover on its own.
251
+ Run `ccst install-everything --apply` to see the whole thing and fix it.
252
+ - **If you never run `ccst` by hand**, the bundled daily `pdata-verify-all` scheduled job does, so
253
+ a machine syncs itself within about 24 hours with no user action.
254
+
216
255
  ## Configure your global CLAUDE.md
217
256
 
218
257
  This is the final required setup step — not included in `install-everything.sh` because it is interactive. Without it, Claude Code sessions have no guidance to use CCST's CLIs or skills, and the 8-digit confirmation gate has no action list to enforce.
@@ -508,7 +547,7 @@ The `send-session-message` skill guides you through choosing a recipient, compos
508
547
 
509
548
  `ccst claude-md install --apply` adds a managed proactive-messaging block to your global `~/.claude/CLAUDE.md`, telling every Claude Code session how to recognise and act on incoming message digests. `ccst claude-md uninstall --apply` removes it. Both commands are idempotent.
510
549
 
511
- The `install-everything.sh` script runs `ccst claude-md install --apply` automatically as part of the standard installation sequence.
550
+ The `install-everything.sh` script runs this step for you, via `ccst install-everything --apply`, as part of the standard installation sequence.
512
551
 
513
552
  ## Scheduled-task catch-up
514
553
 
@@ -742,6 +781,10 @@ The `ccst` umbrella CLI provides hook and skill management, shell helper install
742
781
 
743
782
  ### `ccst hooks install`
744
783
 
784
+ > You normally don't need this: `ccst install-everything --apply` runs it, and `ccst` runs that
785
+ > for you automatically after an upgrade. Use it directly for a custom `--source`/`--hook`/
786
+ > `--target`, or to dry-run one category on its own.
787
+
745
788
  Brings `~/.claude/settings.json` into line with a source `settings.json`: adds
746
789
  the hooks it is missing, and removes any entry naming a hook this build of CCST
747
790
  cannot run. With no `--source`, auto-discovers the bundled
@@ -794,6 +837,10 @@ Run a Claude Code hook by name. See the table above for the supported names.
794
837
 
795
838
  ### `ccst skills install`
796
839
 
840
+ > You normally don't need this: `ccst install-everything --apply` runs it, and `ccst` runs that
841
+ > for you automatically after an upgrade. Use it directly for a custom `--source`/`--target`/
842
+ > `--force`, or to dry-run one category on its own.
843
+
797
844
  Symlink all bundled skills into `~/.claude/skills/`.
798
845
 
799
846
  ```sh
@@ -825,6 +872,10 @@ ccst skills uninstall --skill move-session --apply
825
872
 
826
873
  ### `ccst shell install`
827
874
 
875
+ > You normally don't need this: `ccst install-everything --apply` runs it, and `ccst` runs that
876
+ > for you automatically after an upgrade. Use it directly for a custom `--fragments-dir`, or to
877
+ > dry-run one category on its own.
878
+
828
879
  Write a `ccl()` shell function fragment to `~/.shellrc.d/ccl.sh` (or
829
880
  `--fragments-dir`). ccst does not edit `~/.bashrc`/`~/.zshrc` directly — those
830
881
  files may be managed by something else (e.g. chezmoi). Your shell rc is
@@ -862,6 +913,10 @@ ccst shell uninstall --apply
862
913
 
863
914
  ### `ccst claude-md install`
864
915
 
916
+ > You normally don't need this: `ccst install-everything --apply` runs it, and `ccst` runs that
917
+ > for you automatically after an upgrade. Use it directly for a custom `--target`, or to dry-run
918
+ > one category on its own.
919
+
865
920
  Add or update the inter-session-messaging block in the global `~/.claude/CLAUDE.md`. Idempotent — re-running replaces the existing block rather than appending.
866
921
 
867
922
  ```sh
@@ -884,14 +939,21 @@ ccst claude-md uninstall --apply
884
939
 
885
940
  Run a full health check: PATH for all six CLIs, env vars (`REPO_ROOT`/`PROJ_ROOT`),
886
941
  `~/.claude/settings.json` JSON validity, expected hook registrations present,
887
- skill symlinks correct and pointing at the installed source, version drift
888
- between installed `ccst` and the latest release on PyPI.
942
+ skill symlinks correct and pointing at the installed source, whether your
943
+ config is in sync with the installed version (WARN if not — the next `ccst`
944
+ command fixes it; FAIL if an automatic sync already tried and failed, which
945
+ needs you), and version drift between installed `ccst` and the latest release
946
+ on PyPI.
889
947
 
890
948
  ```sh
891
949
  ccst doctor # checks everything, including PyPI version check
892
950
  ccst doctor --no-pypi # skip the network version check (useful in CI)
951
+ ccst doctor --all # also print OK checks (default: only WARN/FAIL)
893
952
  ```
894
953
 
954
+ By default only WARN/FAIL results are printed — a clean machine is otherwise dozens of `[OK]`
955
+ lines to scroll past. Use `--all` to see the full check list, including everything that passed.
956
+
895
957
  Exit `0` if all checks are OK. Exit `1` if any check is WARN or FAIL.
896
958
 
897
959
  ### `ccst telemetry trim`
@@ -85,7 +85,16 @@ It runs `ccst doctor` at the end so you can see the health check immediately. Re
85
85
  > **Options:** `--from-source` reinstalls from the local clone rather than
86
86
  > PyPI. `--upgrade` forces an upgrade of an existing install.
87
87
 
88
- > **Note:** `install-everything.sh` handles steps 1–5 of setup. Step 6 — adding broader CCST guidance to your global `~/.claude/CLAUDE.md` (session management, 8-digit gate, etc.) — is interactive and must be run separately afterwards. See [Configure your global CLAUDE.md](#configure-your-global-claudemd) below.
88
+ > **Note:** `install-everything.sh` does everything except one interactive step — adding broader
89
+ > CCST guidance to your global `~/.claude/CLAUDE.md` (session management, 8-digit gate, etc.),
90
+ > which must be run separately afterwards. See [Configure your global
91
+ > CLAUDE.md](#configure-your-global-claudemd) below.
92
+
93
+ > **After upgrading** (`uv tool install --reinstall`/`--upgrade`, or `pip`/`pipx` equivalents):
94
+ > nothing to do. The next `ccst` command notices that the installed version doesn't match the
95
+ > version your config was last synced to, runs `install-everything --apply` itself, and tells you
96
+ > on stderr that it did. See [Automatic install sync](#automatic-install-sync) below for the exempt
97
+ > commands, the `CCST_NO_AUTO_SYNC=1` escape hatch, and what happens when the sync fails.
89
98
 
90
99
  **Manual path — step by step:**
91
100
 
@@ -94,11 +103,9 @@ It runs `ccst doctor` at the end so you can see the health check immediately. Re
94
103
  uv tool install cc-session-tools # recommended
95
104
  # pipx install cc-session-tools # alternative
96
105
 
97
- # 2. Install bundled skills, hooks, and the ccl shell function (each command is
98
- # idempotent — safe to re-run after upgrades)
99
- ccst skills install --apply # symlinks skills into ~/.claude/skills/
100
- ccst hooks install --apply # merges all bundled hooks into ~/.claude/settings.json
101
- ccst shell install --apply # writes ccl() to ~/.shellrc.d/ccl.sh
106
+ # 2. Install bundled skills, hooks, the ccl shell function, the CLAUDE.md
107
+ # messaging block and the scheduled jobs (idempotent — safe to re-run)
108
+ ccst install-everything --apply
102
109
 
103
110
  # 3. Verify everything is wired up
104
111
  ccst doctor
@@ -138,10 +145,8 @@ shell (or re-source your rc file) to activate `ccl`.
138
145
  uv tool upgrade cc-session-tools # recommended
139
146
  # pipx upgrade cc-session-tools # alternative
140
147
 
141
- # 2. Pick up any new bundled skills, hooks, and shell helpers
142
- ccst skills install --apply
143
- ccst hooks install --apply
144
- ccst shell install --apply
148
+ # 2. Optional — the next ccst command does this for you automatically
149
+ ccst install-everything --apply
145
150
 
146
151
  # 3. Verify
147
152
  ccst doctor
@@ -156,6 +161,40 @@ source ~/.bashrc # bash
156
161
  source ~/.zshrc # zsh
157
162
  ```
158
163
 
164
+ ### Automatic install sync
165
+
166
+ `uv`, `pip` and `pipx` run no code after unpacking a wheel, so nothing at install time can wire a
167
+ newly-added skill or hook into `~/.claude`. Code is fine — skills symlinks and `ccst hooks run`
168
+ resolve into the tools path the installer reuses in place — but *registration* isn't: a hook added
169
+ in a newer version isn't in `settings.json` until `install-everything` runs, so it silently never
170
+ fires.
171
+
172
+ `ccst` closes that gap itself. Before dispatching any command, it compares the installed version
173
+ against the version your config was last synced to. On a mismatch it runs the five install steps
174
+ (skills, hooks, shell, CLAUDE.md, scheduled jobs), prints two lines to **stderr**, and then runs
175
+ the command you actually asked for:
176
+
177
+ ```
178
+ ccst: install config is out of sync (installed 2.5.0, last synced 2.4.0) — syncing…
179
+ ccst: install config synced to 2.5.0.
180
+ ```
181
+
182
+ - **Nothing is written to stdout**, so `--json` output and scripted callers are unaffected, and
183
+ **your command's exit code is never changed** by the sync.
184
+ - **Exempt commands** (never trigger a sync): `ccst hooks run <verb>` (fires on every tool call in
185
+ every open Claude Code session), `install-everything`, `doctor`, `repair`, `migrate`, and any
186
+ `install`/`uninstall` verb — those are you driving install state by hand, possibly with your own
187
+ `--target`, and a default-target sync underneath them would be self-contradictory.
188
+ - **`CCST_NO_AUTO_SYNC=1`** disables it entirely, for CI, bisecting, or any environment where
189
+ `~/.claude` must not be touched.
190
+ - **If a sync fails** (for example `~/.claude/skills/<name>` exists as a real directory rather than
191
+ a symlink), the full step output is printed to stderr, the failure is remembered, and it backs
192
+ off for six hours rather than retrying on every command — printing one warning line each time
193
+ instead. `ccst doctor` reports that state as a **FAIL**, since it will not recover on its own.
194
+ Run `ccst install-everything --apply` to see the whole thing and fix it.
195
+ - **If you never run `ccst` by hand**, the bundled daily `pdata-verify-all` scheduled job does, so
196
+ a machine syncs itself within about 24 hours with no user action.
197
+
159
198
  ## Configure your global CLAUDE.md
160
199
 
161
200
  This is the final required setup step — not included in `install-everything.sh` because it is interactive. Without it, Claude Code sessions have no guidance to use CCST's CLIs or skills, and the 8-digit confirmation gate has no action list to enforce.
@@ -451,7 +490,7 @@ The `send-session-message` skill guides you through choosing a recipient, compos
451
490
 
452
491
  `ccst claude-md install --apply` adds a managed proactive-messaging block to your global `~/.claude/CLAUDE.md`, telling every Claude Code session how to recognise and act on incoming message digests. `ccst claude-md uninstall --apply` removes it. Both commands are idempotent.
453
492
 
454
- The `install-everything.sh` script runs `ccst claude-md install --apply` automatically as part of the standard installation sequence.
493
+ The `install-everything.sh` script runs this step for you, via `ccst install-everything --apply`, as part of the standard installation sequence.
455
494
 
456
495
  ## Scheduled-task catch-up
457
496
 
@@ -685,6 +724,10 @@ The `ccst` umbrella CLI provides hook and skill management, shell helper install
685
724
 
686
725
  ### `ccst hooks install`
687
726
 
727
+ > You normally don't need this: `ccst install-everything --apply` runs it, and `ccst` runs that
728
+ > for you automatically after an upgrade. Use it directly for a custom `--source`/`--hook`/
729
+ > `--target`, or to dry-run one category on its own.
730
+
688
731
  Brings `~/.claude/settings.json` into line with a source `settings.json`: adds
689
732
  the hooks it is missing, and removes any entry naming a hook this build of CCST
690
733
  cannot run. With no `--source`, auto-discovers the bundled
@@ -737,6 +780,10 @@ Run a Claude Code hook by name. See the table above for the supported names.
737
780
 
738
781
  ### `ccst skills install`
739
782
 
783
+ > You normally don't need this: `ccst install-everything --apply` runs it, and `ccst` runs that
784
+ > for you automatically after an upgrade. Use it directly for a custom `--source`/`--target`/
785
+ > `--force`, or to dry-run one category on its own.
786
+
740
787
  Symlink all bundled skills into `~/.claude/skills/`.
741
788
 
742
789
  ```sh
@@ -768,6 +815,10 @@ ccst skills uninstall --skill move-session --apply
768
815
 
769
816
  ### `ccst shell install`
770
817
 
818
+ > You normally don't need this: `ccst install-everything --apply` runs it, and `ccst` runs that
819
+ > for you automatically after an upgrade. Use it directly for a custom `--fragments-dir`, or to
820
+ > dry-run one category on its own.
821
+
771
822
  Write a `ccl()` shell function fragment to `~/.shellrc.d/ccl.sh` (or
772
823
  `--fragments-dir`). ccst does not edit `~/.bashrc`/`~/.zshrc` directly — those
773
824
  files may be managed by something else (e.g. chezmoi). Your shell rc is
@@ -805,6 +856,10 @@ ccst shell uninstall --apply
805
856
 
806
857
  ### `ccst claude-md install`
807
858
 
859
+ > You normally don't need this: `ccst install-everything --apply` runs it, and `ccst` runs that
860
+ > for you automatically after an upgrade. Use it directly for a custom `--target`, or to dry-run
861
+ > one category on its own.
862
+
808
863
  Add or update the inter-session-messaging block in the global `~/.claude/CLAUDE.md`. Idempotent — re-running replaces the existing block rather than appending.
809
864
 
810
865
  ```sh
@@ -827,14 +882,21 @@ ccst claude-md uninstall --apply
827
882
 
828
883
  Run a full health check: PATH for all six CLIs, env vars (`REPO_ROOT`/`PROJ_ROOT`),
829
884
  `~/.claude/settings.json` JSON validity, expected hook registrations present,
830
- skill symlinks correct and pointing at the installed source, version drift
831
- between installed `ccst` and the latest release on PyPI.
885
+ skill symlinks correct and pointing at the installed source, whether your
886
+ config is in sync with the installed version (WARN if not — the next `ccst`
887
+ command fixes it; FAIL if an automatic sync already tried and failed, which
888
+ needs you), and version drift between installed `ccst` and the latest release
889
+ on PyPI.
832
890
 
833
891
  ```sh
834
892
  ccst doctor # checks everything, including PyPI version check
835
893
  ccst doctor --no-pypi # skip the network version check (useful in CI)
894
+ ccst doctor --all # also print OK checks (default: only WARN/FAIL)
836
895
  ```
837
896
 
897
+ By default only WARN/FAIL results are printed — a clean machine is otherwise dozens of `[OK]`
898
+ lines to scroll past. Use `--all` to see the full check list, including everything that passed.
899
+
838
900
  Exit `0` if all checks are OK. Exit `1` if any check is WARN or FAIL.
839
901
 
840
902
  ### `ccst telemetry trim`
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "cc-session-tools"
7
- version = "2.3.0"
7
+ version = "2.5.0"
8
8
  description = "Claude Code session management CLI tools (ccd, ccr, ccs, claude-code-usage, ccst) and hook library (cccs_hooks)"
9
9
  readme = "README.md"
10
10
  license = { file = "LICENSE" }
@@ -63,6 +63,7 @@ Current subcommands:
63
63
  from __future__ import annotations
64
64
 
65
65
  import argparse
66
+ import contextlib
66
67
  import datetime
67
68
  import importlib
68
69
  import json
@@ -70,7 +71,7 @@ import os
70
71
  import sys
71
72
  from enum import Enum
72
73
  from pathlib import Path
73
- from typing import Any, cast
74
+ from typing import Any, TextIO, cast
74
75
 
75
76
  from cc_session_tools import __version__
76
77
  from cc_session_tools.hooks_install import (
@@ -653,6 +654,7 @@ def _cmd_doctor(args: argparse.Namespace) -> int:
653
654
 
654
655
  from cc_session_tools.lib.pdata import verify as _pdata_verify
655
656
  from cc_session_tools.lib.pdata.init_paths import default_projects_root
657
+ from cc_session_tools.lib import install_sync
656
658
 
657
659
  results = run_all_checks(
658
660
  installed_version=__version__,
@@ -667,6 +669,8 @@ def _cmd_doctor(args: argparse.Namespace) -> int:
667
669
  projects_root=default_projects_root(),
668
670
  pdata_verify_projects=_pdata_verify.discover_projects(),
669
671
  sessions_db_path=store_paths["sessions"],
672
+ synced_version=install_sync.get_synced_version(),
673
+ failed_attempt=install_sync.get_failed_attempt(),
670
674
  )
671
675
 
672
676
  if args.drift or getattr(args, "mode", None) == "drift":
@@ -677,7 +681,7 @@ def _cmd_doctor(args: argparse.Namespace) -> int:
677
681
  print(report)
678
682
  return 1 if unmuted else 0
679
683
 
680
- print(format_results(results))
684
+ print(format_results(results, show_all=getattr(args, "all", False)))
681
685
 
682
686
  any_issue = any(r.status in (Status.WARN, Status.FAIL) for r in results)
683
687
  return 1 if any_issue else 0
@@ -1239,6 +1243,8 @@ def _cmd_sessions_list(args: argparse.Namespace) -> int:
1239
1243
 
1240
1244
 
1241
1245
  def _cmd_repair_sessions(args: argparse.Namespace) -> int:
1246
+ import sqlite3
1247
+
1242
1248
  from cc_session_tools.lib import db as db_lib
1243
1249
  from cc_session_tools.lib import sessions_db, sessions_repair
1244
1250
  from cc_session_tools.lib.roots import RootsConfigError, load_session_roots
@@ -1250,21 +1256,32 @@ def _cmd_repair_sessions(args: argparse.Namespace) -> int:
1250
1256
  print(str(e), file=sys.stderr)
1251
1257
  return 1
1252
1258
 
1253
- if args.execute:
1254
- if not db_path.exists():
1255
- # sqlite3.connect() auto-creates an empty file, so without this check
1256
- # db_lib.backup_to() below would silently back up (and repair() would open)
1257
- # a brand-new, empty sessions.db instead of failing loudly on the mistake.
1258
- print(f"No sessions.db found at {db_path} — nothing to back up or repair.", file=sys.stderr)
1259
- return 1
1260
- backup_dir = db_path.parent / "repair-backups"
1261
- backup_dir.mkdir(parents=True, exist_ok=True)
1262
- stamp = datetime.datetime.now(datetime.timezone.utc).strftime("%Y%m%dT%H%M%SZ")
1263
- backup_path = backup_dir / f"sessions-{stamp}.db"
1264
- db_lib.backup_to(db_path, backup_path)
1265
- print(f"Backed up sessions.db to {backup_path}")
1266
-
1267
- report = sessions_repair.repair(roots, path=db_path, dry_run=not args.execute)
1259
+ # sqlite3.connect() (and the online backup API below) open lazily and
1260
+ # only fail once a statement actually touches the file, so a corrupt-
1261
+ # but-existing sessions.db reaches this try, not the exists() check
1262
+ # above. This is the tool users are told to run to fix store corruption
1263
+ # - both the backup step and the repair itself must fail loudly with a
1264
+ # clear message here, not a raw traceback.
1265
+ try:
1266
+ if args.execute:
1267
+ if not db_path.exists():
1268
+ # sqlite3.connect() auto-creates an empty file, so without this
1269
+ # check db_lib.backup_to() below would silently back up (and
1270
+ # repair() would open) a brand-new, empty sessions.db instead
1271
+ # of failing loudly on the mistake.
1272
+ print(f"No sessions.db found at {db_path} — nothing to back up or repair.", file=sys.stderr)
1273
+ return 1
1274
+ backup_dir = db_path.parent / "repair-backups"
1275
+ backup_dir.mkdir(parents=True, exist_ok=True)
1276
+ stamp = datetime.datetime.now(datetime.timezone.utc).strftime("%Y%m%dT%H%M%SZ")
1277
+ backup_path = backup_dir / f"sessions-{stamp}.db"
1278
+ db_lib.backup_to(db_path, backup_path)
1279
+ print(f"Backed up sessions.db to {backup_path}")
1280
+
1281
+ report = sessions_repair.repair(roots, path=db_path, dry_run=not args.execute)
1282
+ except sqlite3.DatabaseError as exc:
1283
+ print(f"{db_path} exists but failed to open: {exc}", file=sys.stderr)
1284
+ return 1
1268
1285
  if not any((report.repaired, report.unresolved, report.ambiguous, report.conflicts)):
1269
1286
  print("No non-absolute project_dir rows found in sessions.db.")
1270
1287
  return 0
@@ -1421,17 +1438,38 @@ def _cmd_ccsched_jobs_install(args: argparse.Namespace) -> int:
1421
1438
  # ---------- install-everything ----------
1422
1439
 
1423
1440
 
1424
- def _cmd_install_everything(args: argparse.Namespace) -> int:
1425
- """Run all install steps in sequence, then health-check."""
1426
- apply: bool = args.apply
1427
- no_pypi: bool = args.no_pypi
1428
-
1429
- skills_target = getattr(args, "skills_target", None)
1430
- hooks_target = getattr(args, "hooks_target", None) or str(
1431
- Path.home() / ".claude" / "settings.json"
1432
- )
1433
- fragments_dir = getattr(args, "fragments_dir", None)
1434
- claude_md_target = getattr(args, "claude_md_target", None)
1441
+ def run_install_everything(
1442
+ *,
1443
+ apply: bool,
1444
+ stream: TextIO,
1445
+ health_check: bool,
1446
+ no_pypi: bool = False,
1447
+ skills_target: str | None = None,
1448
+ hooks_target: str | None = None,
1449
+ fragments_dir: str | None = None,
1450
+ claude_md_target: str | None = None,
1451
+ ) -> int:
1452
+ """Run the five install steps, optionally followed by a health check.
1453
+
1454
+ Returns the worst rc the five steps produced; the health check's own rc is
1455
+ deliberately not part of it, matching the diagnostic-not-gate role it has
1456
+ always had here.
1457
+
1458
+ `stream` receives every step's progress output. The five step functions
1459
+ print to stdout directly, so the loop runs under
1460
+ contextlib.redirect_stdout(stream): the CLI adapter passes sys.stdout (a
1461
+ no-op passthrough) and install_sync.ensure_synced passes a StringIO it
1462
+ discards on success. Auto-apply must not write to stdout at all -
1463
+ `ccst sessions list --json` emits machine-readable stdout, and
1464
+ scheduler/worker.py carries a job's stdout into the ledger as its recorded
1465
+ findings.
1466
+
1467
+ `health_check=False` is what auto-apply uses: the five steps are 16.8 ms,
1468
+ the trailing `ccst doctor` is ~1.55 s dominated by its PyPI network call.
1469
+ An auto-apply is not a diagnostic run and must not take a network
1470
+ dependency on someone else's command.
1471
+ """
1472
+ hooks_target = hooks_target or str(Path.home() / ".claude" / "settings.json")
1435
1473
 
1436
1474
  steps: list[tuple[str, str, object]] = [
1437
1475
  (
@@ -1477,37 +1515,73 @@ def _cmd_install_everything(args: argparse.Namespace) -> int:
1477
1515
  "ccsched-jobs": _cmd_ccsched_jobs_install,
1478
1516
  }
1479
1517
 
1480
- # +1 accounts for the trailing health check below, which isn't itself a `steps` entry.
1481
- total_steps = len(steps) + 1
1518
+ # +1 accounts for the trailing health check, which isn't itself a `steps` entry.
1519
+ total_steps = len(steps) + (1 if health_check else 0)
1482
1520
  overall_rc = 0
1483
- for i, (label, key, step_args) in enumerate(steps, start=1):
1484
- print(f"\n=== {i}/{total_steps} {label} ===")
1485
- rc = dispatch[key](step_args) # type: ignore[operator]
1486
- if rc != 0:
1487
- overall_rc = rc
1521
+ with contextlib.redirect_stdout(stream):
1522
+ for i, (label, key, step_args) in enumerate(steps, start=1):
1523
+ print(f"\n=== {i}/{total_steps} {label} ===")
1524
+ rc = dispatch[key](step_args) # type: ignore[operator]
1525
+ if rc != 0:
1526
+ overall_rc = rc
1527
+
1528
+ if apply and overall_rc == 0:
1529
+ import sqlite3
1530
+
1531
+ from cc_session_tools.lib import install_sync
1532
+ try:
1533
+ install_sync.record_synced(__version__)
1534
+ except sqlite3.DatabaseError as exc:
1535
+ # A corrupt sessions.db must not erase the five install steps'
1536
+ # already-successful work (and their printed summary) that ran
1537
+ # just above - print a clear warning and continue. Letting this
1538
+ # propagate would also be self-defeating: this is the exact
1539
+ # command the out-of-sync warning tells a user to run.
1540
+ print(
1541
+ f" warning: could not record the install-everything sync marker "
1542
+ f"({exc}) - sessions.db may be corrupt; run `ccst repair sessions` "
1543
+ "to investigate",
1544
+ file=sys.stderr,
1545
+ )
1488
1546
 
1489
- print(f"\n=== {total_steps}/{total_steps} Health check ===")
1490
- _cmd_doctor(
1491
- argparse.Namespace(
1492
- settings=None,
1493
- skills_dir=None,
1494
- no_pypi=no_pypi,
1495
- drift=False,
1496
- mute=None,
1497
- unmute=None,
1498
- list_mutes=False,
1499
- mutes_file=None,
1500
- mode=None,
1501
- )
1502
- )
1547
+ if health_check:
1548
+ print(f"\n=== {total_steps}/{total_steps} Health check ===")
1549
+ _cmd_doctor(
1550
+ argparse.Namespace(
1551
+ settings=None,
1552
+ skills_dir=None,
1553
+ no_pypi=no_pypi,
1554
+ drift=False,
1555
+ mute=None,
1556
+ unmute=None,
1557
+ list_mutes=False,
1558
+ mutes_file=None,
1559
+ mode=None,
1560
+ )
1561
+ )
1503
1562
 
1504
- if not apply:
1505
- print("\nDry run complete — re-run with --apply to write all changes.")
1506
- else:
1507
- print("\nAll install steps complete.")
1563
+ if not apply:
1564
+ print("\nDry run complete — re-run with --apply to write all changes.")
1565
+ else:
1566
+ print("\nAll install steps complete.")
1508
1567
  return overall_rc
1509
1568
 
1510
1569
 
1570
+ def _cmd_install_everything(args: argparse.Namespace) -> int:
1571
+ """argparse adapter for run_install_everything: the interactive CLI path,
1572
+ which streams to stdout and always ends with the health check."""
1573
+ return run_install_everything(
1574
+ apply=args.apply,
1575
+ stream=sys.stdout,
1576
+ health_check=True,
1577
+ no_pypi=args.no_pypi,
1578
+ skills_target=getattr(args, "skills_target", None),
1579
+ hooks_target=getattr(args, "hooks_target", None),
1580
+ fragments_dir=getattr(args, "fragments_dir", None),
1581
+ claude_md_target=getattr(args, "claude_md_target", None),
1582
+ )
1583
+
1584
+
1511
1585
  # ---------- arg parser ----------
1512
1586
 
1513
1587
 
@@ -1674,6 +1748,11 @@ def _build_parser() -> argparse.ArgumentParser:
1674
1748
  action="store_true",
1675
1749
  help="Skip the PyPI version-drift check",
1676
1750
  )
1751
+ doctor_parser.add_argument(
1752
+ "--all",
1753
+ action="store_true",
1754
+ help="Show every check result, including OK (default: only non-OK)",
1755
+ )
1677
1756
  doctor_parser.add_argument(
1678
1757
  "--drift",
1679
1758
  action="store_true",
@@ -2136,7 +2215,10 @@ def _build_parser() -> argparse.ArgumentParser:
2136
2215
  "install-everything",
2137
2216
  help=(
2138
2217
  "Run all install steps (skills, hooks, shell, claude-md, scheduled jobs) then "
2139
- "health-check. Dry run by default; pass --apply to write changes."
2218
+ "health-check. Dry run by default; pass --apply to write changes. ccst runs "
2219
+ "this for you automatically after an upgrade — use it directly to preview the "
2220
+ "changes, to pass per-category target overrides, or to see why an automatic "
2221
+ "sync failed."
2140
2222
  ),
2141
2223
  )
2142
2224
  ie_parser.add_argument(
@@ -2181,6 +2263,35 @@ def main() -> None:
2181
2263
  parser.print_help(sys.stderr)
2182
2264
  sys.exit(1)
2183
2265
 
2266
+ from cc_session_tools.lib import install_sync
2267
+
2268
+ # Bring ~/.claude's registration into line with the installed version
2269
+ # before dispatching. What goes stale on an upgrade is registration, not
2270
+ # code: skills symlinks and `ccst hooks run`'s dynamic import both resolve
2271
+ # into the uv tools path that --reinstall reuses in place, but a hook or
2272
+ # skill added in a newer version isn't wired into settings.json /
2273
+ # ~/.claude/skills until install-everything runs, so it silently never
2274
+ # fires. Wheels have no post-install hook, so the first ccst process after
2275
+ # an upgrade is the earliest possible moment.
2276
+ #
2277
+ # Cost on a carrier invocation is one readonly SQLite open/read/close,
2278
+ # 0.56 ms against a 94 ms bare process start. `ccst hooks run <verb>` is
2279
+ # exempt and doesn't pay even that - not for the per-call cost but for the
2280
+ # invocation count (every tool call in every open session) and because
2281
+ # rewriting settings.json from inside a hook Claude Code invoked from
2282
+ # settings.json is a race no atomic write makes tidy. See
2283
+ # install_sync.is_auto_sync_exempt for the full exempt set.
2284
+ #
2285
+ # Placement is after parse_args and after the usage check on purpose: an
2286
+ # invalid command line still fails at argparse without triggering an
2287
+ # apply, --version/--help/bare ccst never trigger one, and a successful
2288
+ # apply is in place before the requested command runs.
2289
+ install_sync.ensure_synced(
2290
+ noun=args.noun,
2291
+ verb=getattr(args, "verb", None),
2292
+ installed_version=__version__,
2293
+ )
2294
+
2184
2295
  if args.noun == "hooks":
2185
2296
  if args.verb == "install":
2186
2297
  sys.exit(_cmd_hooks_install(args))