cc-session-tools 3.6.1__tar.gz → 3.7.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 (288) hide show
  1. {cc_session_tools-3.6.1/src/cc_session_tools.egg-info → cc_session_tools-3.7.0}/PKG-INFO +3 -3
  2. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/README.md +2 -2
  3. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/pyproject.toml +1 -1
  4. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/cc_session_tools/cli/ccst.py +81 -0
  5. cc_session_tools-3.7.0/src/cc_session_tools/lib/bun_tools.py +39 -0
  6. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/cc_session_tools/lib/doctor.py +68 -0
  7. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/cc_session_tools/skills/analyse-cc-usage/SKILL.md +22 -2
  8. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0/src/cc_session_tools.egg-info}/PKG-INFO +3 -3
  9. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/cc_session_tools.egg-info/SOURCES.txt +6 -0
  10. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/claude_code_usage/ccusage_wrapper.py +12 -6
  11. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/hooks/bash_security_review.py +166 -13
  12. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/hooks/cache.py +94 -0
  13. cc_session_tools-3.7.0/src/hooks/script_allowlist.py +145 -0
  14. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/tests/test_bash_security_review.py +78 -4
  15. cc_session_tools-3.7.0/tests/test_bash_security_review_allowlist.py +330 -0
  16. cc_session_tools-3.7.0/tests/test_bun_tools.py +67 -0
  17. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/tests/test_ccst_doctor.py +101 -0
  18. cc_session_tools-3.7.0/tests/test_ccst_hooks_allowlist.py +114 -0
  19. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/tests/test_ccusage_wrapper.py +55 -0
  20. cc_session_tools-3.7.0/tests/test_script_allowlist.py +288 -0
  21. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/LICENSE +0 -0
  22. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/setup.cfg +0 -0
  23. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/cc_session_tools/__init__.py +0 -0
  24. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/cc_session_tools/cli/__init__.py +0 -0
  25. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/cc_session_tools/cli/ccd.py +0 -0
  26. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/cc_session_tools/cli/ccmsg.py +0 -0
  27. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/cc_session_tools/cli/ccr.py +0 -0
  28. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/cc_session_tools/cli/ccs.py +0 -0
  29. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/cc_session_tools/cli/ccsched.py +0 -0
  30. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/cc_session_tools/cli/migrate_ccmsg.py +0 -0
  31. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/cc_session_tools/cli/migrate_ccsched.py +0 -0
  32. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/cc_session_tools/cli/migrate_sessions_db.py +0 -0
  33. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/cc_session_tools/cli/migrate_telemetry.py +0 -0
  34. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/cc_session_tools/config/hooks-bundle.json +0 -0
  35. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/cc_session_tools/config/session-tag-hook.json +0 -0
  36. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/cc_session_tools/hooks_install.py +0 -0
  37. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/cc_session_tools/lib/__init__.py +0 -0
  38. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/cc_session_tools/lib/claude_flags.py +0 -0
  39. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/cc_session_tools/lib/claude_md_install.py +0 -0
  40. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/cc_session_tools/lib/context_overrides.py +0 -0
  41. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/cc_session_tools/lib/db.py +0 -0
  42. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/cc_session_tools/lib/debug.py +0 -0
  43. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/cc_session_tools/lib/doctor_mutes.py +0 -0
  44. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/cc_session_tools/lib/hook_registry.py +0 -0
  45. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/cc_session_tools/lib/install_sync.py +0 -0
  46. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/cc_session_tools/lib/levenshtein.py +0 -0
  47. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/cc_session_tools/lib/machine_identity.py +0 -0
  48. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/cc_session_tools/lib/messaging/__init__.py +0 -0
  49. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/cc_session_tools/lib/messaging/addressing.py +0 -0
  50. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/cc_session_tools/lib/messaging/cursor.py +0 -0
  51. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/cc_session_tools/lib/messaging/lock.py +0 -0
  52. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/cc_session_tools/lib/messaging/message.py +0 -0
  53. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/cc_session_tools/lib/messaging/move_safety.py +0 -0
  54. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/cc_session_tools/lib/messaging/repository.py +0 -0
  55. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/cc_session_tools/lib/messaging/retention.py +0 -0
  56. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/cc_session_tools/lib/messaging/service.py +0 -0
  57. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/cc_session_tools/lib/messaging/store.py +0 -0
  58. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/cc_session_tools/lib/occupancy.py +0 -0
  59. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/cc_session_tools/lib/paths.py +0 -0
  60. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/cc_session_tools/lib/pdata/__init__.py +0 -0
  61. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/cc_session_tools/lib/pdata/backup.py +0 -0
  62. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/cc_session_tools/lib/pdata/classify.py +0 -0
  63. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/cc_session_tools/lib/pdata/cutover.py +0 -0
  64. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/cc_session_tools/lib/pdata/dump.py +0 -0
  65. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/cc_session_tools/lib/pdata/formatting.py +0 -0
  66. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/cc_session_tools/lib/pdata/importers.py +0 -0
  67. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/cc_session_tools/lib/pdata/init_paths.py +0 -0
  68. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/cc_session_tools/lib/pdata/init_service.py +0 -0
  69. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/cc_session_tools/lib/pdata/manifest.py +0 -0
  70. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/cc_session_tools/lib/pdata/naming.py +0 -0
  71. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/cc_session_tools/lib/pdata/rehydrate.py +0 -0
  72. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/cc_session_tools/lib/pdata/rename_group.py +0 -0
  73. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/cc_session_tools/lib/pdata/reorganize.py +0 -0
  74. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/cc_session_tools/lib/pdata/repository.py +0 -0
  75. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/cc_session_tools/lib/pdata/resolve.py +0 -0
  76. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/cc_session_tools/lib/pdata/service.py +0 -0
  77. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/cc_session_tools/lib/pdata/session_output.py +0 -0
  78. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/cc_session_tools/lib/pdata/store.py +0 -0
  79. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/cc_session_tools/lib/pdata/sync_check.py +0 -0
  80. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/cc_session_tools/lib/pdata/sync_lock.py +0 -0
  81. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/cc_session_tools/lib/pdata/sync_notify.py +0 -0
  82. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/cc_session_tools/lib/pdata/vector_clock.py +0 -0
  83. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/cc_session_tools/lib/pdata/vector_clock_store.py +0 -0
  84. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/cc_session_tools/lib/pdata/verify.py +0 -0
  85. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/cc_session_tools/lib/pdata/write_log.py +0 -0
  86. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/cc_session_tools/lib/picker.py +0 -0
  87. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/cc_session_tools/lib/proc_lock.py +0 -0
  88. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/cc_session_tools/lib/prompts.py +0 -0
  89. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/cc_session_tools/lib/roots.py +0 -0
  90. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/cc_session_tools/lib/rules.py +0 -0
  91. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/cc_session_tools/lib/scheduler/__init__.py +0 -0
  92. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/cc_session_tools/lib/scheduler/bundled_jobs.py +0 -0
  93. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/cc_session_tools/lib/scheduler/cadence.py +0 -0
  94. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/cc_session_tools/lib/scheduler/cursor.py +0 -0
  95. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/cc_session_tools/lib/scheduler/digest.py +0 -0
  96. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/cc_session_tools/lib/scheduler/due.py +0 -0
  97. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/cc_session_tools/lib/scheduler/duration.py +0 -0
  98. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/cc_session_tools/lib/scheduler/jobspec.py +0 -0
  99. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/cc_session_tools/lib/scheduler/ledger.py +0 -0
  100. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/cc_session_tools/lib/scheduler/lock.py +0 -0
  101. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/cc_session_tools/lib/scheduler/notify.py +0 -0
  102. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/cc_session_tools/lib/scheduler/reconcile.py +0 -0
  103. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/cc_session_tools/lib/scheduler/registry.py +0 -0
  104. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/cc_session_tools/lib/scheduler/runner.py +0 -0
  105. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/cc_session_tools/lib/scheduler/state.py +0 -0
  106. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/cc_session_tools/lib/scheduler/store.py +0 -0
  107. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/cc_session_tools/lib/scheduler/surface.py +0 -0
  108. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/cc_session_tools/lib/scheduler/throttle.py +0 -0
  109. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/cc_session_tools/lib/scheduler/worker.py +0 -0
  110. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/cc_session_tools/lib/session_gc.py +0 -0
  111. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/cc_session_tools/lib/sessions.py +0 -0
  112. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/cc_session_tools/lib/sessions_db.py +0 -0
  113. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/cc_session_tools/lib/sessions_repair.py +0 -0
  114. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/cc_session_tools/lib/shell_install.py +0 -0
  115. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/cc_session_tools/lib/tasklist.py +0 -0
  116. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/cc_session_tools/lib/telemetry_store.py +0 -0
  117. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/cc_session_tools/prompts/pdata-migration-claude-md-update.md +0 -0
  118. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/cc_session_tools/prompts/pdata-migration-skills-update.md +0 -0
  119. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/cc_session_tools/skills/clean-hook-sessions/SKILL.md +0 -0
  120. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/cc_session_tools/skills/clean-hook-sessions/scripts/clean-hook-sessions.py +0 -0
  121. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/cc_session_tools/skills/compact-smart/SKILL.md +0 -0
  122. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/cc_session_tools/skills/context-override/SKILL.md +0 -0
  123. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/cc_session_tools/skills/delete-sessions/SKILL.md +0 -0
  124. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/cc_session_tools/skills/delete-sessions/scripts/delete_sessions.py +0 -0
  125. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/cc_session_tools/skills/do-executor-critic-assessor-loop/SKILL.md +0 -0
  126. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/cc_session_tools/skills/extract-pptx/SKILL.md +0 -0
  127. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/cc_session_tools/skills/extract-pptx/scripts/extract_pptx.py +0 -0
  128. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/cc_session_tools/skills/extract-to-text/SKILL.md +0 -0
  129. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/cc_session_tools/skills/extract-to-text/scripts/extract_to_text.py +0 -0
  130. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/cc_session_tools/skills/find-claude-code-session/SKILL.md +0 -0
  131. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/cc_session_tools/skills/generate-8digit-code/SKILL.md +0 -0
  132. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/cc_session_tools/skills/generate-8digit-code/scripts/generate_8digit_code.py +0 -0
  133. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/cc_session_tools/skills/list-empty-sessions/SKILL.md +0 -0
  134. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/cc_session_tools/skills/list-empty-sessions/scripts/list_empty_sessions.py +0 -0
  135. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/cc_session_tools/skills/manage-recurring-cc-jobs-using-ccsched/SKILL.md +0 -0
  136. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/cc_session_tools/skills/move-session/SKILL.md +0 -0
  137. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/cc_session_tools/skills/move-session/hooks/sessionstart-pending-rename.sh +0 -0
  138. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/cc_session_tools/skills/move-session/scripts/cc_session_rules.py +0 -0
  139. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/cc_session_tools/skills/move-session/scripts/move_session.py +0 -0
  140. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/cc_session_tools/skills/pm-pdata-design-schema/SKILL.md +0 -0
  141. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/cc_session_tools/skills/pm-pdata-do-audit-and-prepare-to-migrate/SKILL.md +0 -0
  142. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/cc_session_tools/skills/pm-pdata-do-init/SKILL.md +0 -0
  143. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/cc_session_tools/skills/pm-pdata-do-manual-migration/SKILL.md +0 -0
  144. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/cc_session_tools/skills/pm-pdata-resolve-conflicts/SKILL.md +0 -0
  145. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/cc_session_tools/skills/pm-project-layout-reference/SKILL.md +0 -0
  146. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/cc_session_tools/skills/pm-update-central-files/SKILL.md +0 -0
  147. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/cc_session_tools/skills/reduce-persistent-context/CALIBRATION.md +0 -0
  148. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/cc_session_tools/skills/reduce-persistent-context/SKILL.md +0 -0
  149. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/cc_session_tools/skills/reduce-persistent-context/scripts/analyze_context.py +0 -0
  150. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/cc_session_tools/skills/reduce-persistent-context/scripts/duplicates.py +0 -0
  151. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/cc_session_tools/skills/reduce-persistent-context/scripts/measure.py +0 -0
  152. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/cc_session_tools/skills/reduce-persistent-context/scripts/report.py +0 -0
  153. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/cc_session_tools/skills/reduce-persistent-context/scripts/tokens.py +0 -0
  154. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/cc_session_tools/skills/reduce-persistent-context/scripts/usage.py +0 -0
  155. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/cc_session_tools/skills/select-agent-model/SKILL.md +0 -0
  156. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/cc_session_tools/skills/send-session-message/SKILL.md +0 -0
  157. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/cc_session_tools/skills/update-command-cache/SKILL.md +0 -0
  158. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/cc_session_tools/skills/update-command-cache/scripts/update_command_cache.py +0 -0
  159. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/cc_session_tools.egg-info/dependency_links.txt +0 -0
  160. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/cc_session_tools.egg-info/entry_points.txt +0 -0
  161. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/cc_session_tools.egg-info/requires.txt +0 -0
  162. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/cc_session_tools.egg-info/top_level.txt +0 -0
  163. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/claude_code_usage/__init__.py +0 -0
  164. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/claude_code_usage/attribution.py +0 -0
  165. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/claude_code_usage/cache.py +0 -0
  166. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/claude_code_usage/cli.py +0 -0
  167. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/claude_code_usage/data/pricing.json +0 -0
  168. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/claude_code_usage/parent_inference.py +0 -0
  169. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/claude_code_usage/parser.py +0 -0
  170. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/claude_code_usage/pricing.py +0 -0
  171. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/claude_code_usage/query.py +0 -0
  172. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/claude_code_usage/report.py +0 -0
  173. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/claude_code_usage/schema.py +0 -0
  174. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/claude_code_usage/session_names.py +0 -0
  175. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/hooks/__init__.py +0 -0
  176. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/hooks/after_response.py +0 -0
  177. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/hooks/bash_hard_deny.py +0 -0
  178. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/hooks/catchup.py +0 -0
  179. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/hooks/confirm_8digit.py +0 -0
  180. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/hooks/context_window_warning.py +0 -0
  181. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/hooks/last_screenshot.py +0 -0
  182. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/hooks/marker_allow.py +0 -0
  183. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/hooks/markers.py +0 -0
  184. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/hooks/messaging_deliver.py +0 -0
  185. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/hooks/model_info.py +0 -0
  186. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/hooks/normalise.py +0 -0
  187. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/hooks/pdata_sync.py +0 -0
  188. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/hooks/pending_migration.py +0 -0
  189. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/hooks/pending_rename.py +0 -0
  190. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/hooks/session_tag.py +0 -0
  191. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/hooks/stats.py +0 -0
  192. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/hooks/telemetry.py +0 -0
  193. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/hooks/telemetry_query.py +0 -0
  194. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/hooks/telemetry_trim.py +0 -0
  195. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/hooks/transcript.py +0 -0
  196. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/src/hooks/worklog_guard.py +0 -0
  197. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/tests/test_after_response.py +0 -0
  198. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/tests/test_attribution.py +0 -0
  199. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/tests/test_bash_hard_deny.py +0 -0
  200. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/tests/test_cache.py +0 -0
  201. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/tests/test_cache_sqlite.py +0 -0
  202. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/tests/test_ccr_orphans.py +0 -0
  203. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/tests/test_ccs_emptiness.py +0 -0
  204. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/tests/test_ccs_eta.py +0 -0
  205. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/tests/test_ccs_list_mode.py +0 -0
  206. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/tests/test_ccs_scope_flags.py +0 -0
  207. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/tests/test_ccs_sentinel_sort.py +0 -0
  208. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/tests/test_ccs_session_counts.py +0 -0
  209. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/tests/test_ccst_bundle_discovery.py +0 -0
  210. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/tests/test_ccst_ccsched_jobs_cli.py +0 -0
  211. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/tests/test_ccst_cli.py +0 -0
  212. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/tests/test_ccst_context_override_cli.py +0 -0
  213. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/tests/test_ccst_gc_prune.py +0 -0
  214. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/tests/test_ccst_gc_report.py +0 -0
  215. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/tests/test_ccst_hook_dispatcher.py +0 -0
  216. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/tests/test_ccst_hooks_install_prune.py +0 -0
  217. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/tests/test_ccst_hooks_install_zero_arg.py +0 -0
  218. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/tests/test_ccst_hooks_uninstall.py +0 -0
  219. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/tests/test_ccst_install_everything.py +0 -0
  220. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/tests/test_ccst_machine_identity_cli.py +0 -0
  221. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/tests/test_ccst_main_gate.py +0 -0
  222. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/tests/test_ccst_pdata_cli.py +0 -0
  223. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/tests/test_ccst_pdata_init_cli.py +0 -0
  224. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/tests/test_ccst_pdata_reconcile_cli.py +0 -0
  225. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/tests/test_ccst_pdata_rename_group_cli.py +0 -0
  226. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/tests/test_ccst_pdata_reorganize_cli.py +0 -0
  227. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/tests/test_ccst_pdata_sync_cli.py +0 -0
  228. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/tests/test_ccst_pdata_verify_cli.py +0 -0
  229. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/tests/test_ccst_repair_sessions_cli.py +0 -0
  230. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/tests/test_ccst_sessions_cli.py +0 -0
  231. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/tests/test_ccst_shell_install.py +0 -0
  232. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/tests/test_ccst_skills_install.py +0 -0
  233. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/tests/test_ccst_skills_uninstall.py +0 -0
  234. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/tests/test_ccst_telemetry_query.py +0 -0
  235. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/tests/test_ccst_telemetry_trim.py +0 -0
  236. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/tests/test_claude_flags.py +0 -0
  237. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/tests/test_claude_md_install.py +0 -0
  238. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/tests/test_cli.py +0 -0
  239. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/tests/test_cli_ccd.py +0 -0
  240. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/tests/test_cli_ccd_dry_run.py +0 -0
  241. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/tests/test_cli_ccr.py +0 -0
  242. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/tests/test_cli_ccs.py +0 -0
  243. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/tests/test_cli_version.py +0 -0
  244. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/tests/test_confirm_8digit.py +0 -0
  245. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/tests/test_context_overrides.py +0 -0
  246. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/tests/test_context_window_warning.py +0 -0
  247. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/tests/test_db.py +0 -0
  248. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/tests/test_debug.py +0 -0
  249. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/tests/test_doctor_mutes.py +0 -0
  250. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/tests/test_empty_session.py +0 -0
  251. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/tests/test_hook_cache.py +0 -0
  252. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/tests/test_hooks_install.py +0 -0
  253. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/tests/test_install_sync.py +0 -0
  254. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/tests/test_last_screenshot.py +0 -0
  255. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/tests/test_levenshtein.py +0 -0
  256. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/tests/test_machine_identity.py +0 -0
  257. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/tests/test_marker_allow.py +0 -0
  258. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/tests/test_migrate_ccmsg.py +0 -0
  259. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/tests/test_migrate_ccsched.py +0 -0
  260. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/tests/test_migrate_sessions_db.py +0 -0
  261. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/tests/test_migrate_telemetry.py +0 -0
  262. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/tests/test_model_info.py +0 -0
  263. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/tests/test_normalise.py +0 -0
  264. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/tests/test_occupancy.py +0 -0
  265. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/tests/test_parent_inference.py +0 -0
  266. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/tests/test_parser.py +0 -0
  267. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/tests/test_paths.py +0 -0
  268. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/tests/test_pending_migration_hook.py +0 -0
  269. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/tests/test_picker.py +0 -0
  270. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/tests/test_pricing.py +0 -0
  271. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/tests/test_proc_lock.py +0 -0
  272. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/tests/test_prompts.py +0 -0
  273. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/tests/test_query.py +0 -0
  274. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/tests/test_report.py +0 -0
  275. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/tests/test_roots.py +0 -0
  276. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/tests/test_rules.py +0 -0
  277. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/tests/test_scheduler_bundled_jobs.py +0 -0
  278. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/tests/test_schema.py +0 -0
  279. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/tests/test_session_names.py +0 -0
  280. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/tests/test_session_tag.py +0 -0
  281. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/tests/test_sessions.py +0 -0
  282. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/tests/test_sessions_db.py +0 -0
  283. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/tests/test_sessions_repair.py +0 -0
  284. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/tests/test_tasklist.py +0 -0
  285. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/tests/test_telemetry.py +0 -0
  286. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/tests/test_telemetry_store.py +0 -0
  287. {cc_session_tools-3.6.1 → cc_session_tools-3.7.0}/tests/test_transcript.py +0 -0
  288. {cc_session_tools-3.6.1 → cc_session_tools-3.7.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: 3.6.1
3
+ Version: 3.7.0
4
4
  Summary: Claude Code session management CLI tools (ccd, ccr, ccs, claude-code-usage, ccst) and hook library (hooks package)
5
5
  Author: raffishquartan
6
6
  License: MIT License
@@ -105,7 +105,7 @@ bundled scheduled jobs:
105
105
  | **`session-tag`** (SessionStart) | Writes a `<uuid>.tag` file so `claude-code-usage` can map session UUIDs to human-readable names. |
106
106
  | **`last-screenshot`** (UserPromptSubmit) | Resolves your newest screenshot for the `>lss` token and injects its path. Requires `CCST_SCREENSHOT_DIR`. |
107
107
  | **`bash-hard-deny`** (PreToolUse) | Categorical hard-deny gate for Bash: destructive file ops (`rm`/`rmdir`/`unlink`/`shred`, incl. inline python/node and script-file/heredoc forms), delete-by-move to a tmp-like location, `git branch`/`git push` branch deletion, `gh api`/`gh release` delete, destructive curl/wget methods, `sudo`, and direct telemetry-log reads. Runs before every other Bash hook; a match here can never be overridden in-session (the message tells you to run the command yourself in a separate terminal). |
108
- | **`bash-security-review`** (PreToolUse) | Tiered Bash command security review with an allowlist cache and LLM fallback. |
108
+ | **`bash-security-review`** (PreToolUse) | Tiered Bash command security review: trivial/read-only pre-filters, heuristic escalation, a reviewed-script allowlist (script path + content hash, managed with `ccst hooks allowlist list\|add\|remove\|verify`), a command cache, and a slimmed `claude -p` LLM fallback (~770 tokens per review instead of ~50k+). |
109
109
  | **`marker-allow`** (PreToolUse) | Auto-approves a bare `touch` of a skill marker under `~/.cache/claude/markers/` (and nothing else), so marker-gated skills can refresh their TTL marker without a permission prompt. |
110
110
  | **`confirm-8digit`** (PreToolUse) | Blocks a configurable set of high-stakes tool calls unless the user repeats back an 8-digit confirmation code. |
111
111
  | **`after-response`** (Stop) | Touches a `.last-active` sentinel so `ccs --order-by active` can sort sessions by recency of Claude activity. |
@@ -151,7 +151,7 @@ If you've ever tried to remember which `1f4a8b3c-...` UUID is the session where
151
151
 
152
152
  - **Python 3.11+** (3.12+ recommended)
153
153
  - **The `claude` CLI on your `$PATH`.** Install it first via [the official Claude Code instructions](https://docs.anthropic.com/en/docs/claude-code/setup) and verify with `claude --version`.
154
- - **`ccusage` (optional)** - if on `$PATH`, `claude-code-usage reconcile` cross-checks dollar totals against it. Skipped gracefully if missing.
154
+ - **`ccusage` (optional)** - if on `$PATH` (or in bun's global bin dir, `~/.bun/bin`), `claude-code-usage reconcile` cross-checks dollar totals against it. Skipped gracefully if missing. Needs `bun` to install; `ccst doctor` reports both under `deps:bun` / `deps:ccusage` and prints the install command. See the `analyse-cc-usage` skill's setup section.
155
155
  - **`ripgrep` (optional)** - `ccs --contents` prefers `rg`; falls back to threaded Python `grep` if missing.
156
156
 
157
157
  ### Install and set up
@@ -48,7 +48,7 @@ bundled scheduled jobs:
48
48
  | **`session-tag`** (SessionStart) | Writes a `<uuid>.tag` file so `claude-code-usage` can map session UUIDs to human-readable names. |
49
49
  | **`last-screenshot`** (UserPromptSubmit) | Resolves your newest screenshot for the `>lss` token and injects its path. Requires `CCST_SCREENSHOT_DIR`. |
50
50
  | **`bash-hard-deny`** (PreToolUse) | Categorical hard-deny gate for Bash: destructive file ops (`rm`/`rmdir`/`unlink`/`shred`, incl. inline python/node and script-file/heredoc forms), delete-by-move to a tmp-like location, `git branch`/`git push` branch deletion, `gh api`/`gh release` delete, destructive curl/wget methods, `sudo`, and direct telemetry-log reads. Runs before every other Bash hook; a match here can never be overridden in-session (the message tells you to run the command yourself in a separate terminal). |
51
- | **`bash-security-review`** (PreToolUse) | Tiered Bash command security review with an allowlist cache and LLM fallback. |
51
+ | **`bash-security-review`** (PreToolUse) | Tiered Bash command security review: trivial/read-only pre-filters, heuristic escalation, a reviewed-script allowlist (script path + content hash, managed with `ccst hooks allowlist list\|add\|remove\|verify`), a command cache, and a slimmed `claude -p` LLM fallback (~770 tokens per review instead of ~50k+). |
52
52
  | **`marker-allow`** (PreToolUse) | Auto-approves a bare `touch` of a skill marker under `~/.cache/claude/markers/` (and nothing else), so marker-gated skills can refresh their TTL marker without a permission prompt. |
53
53
  | **`confirm-8digit`** (PreToolUse) | Blocks a configurable set of high-stakes tool calls unless the user repeats back an 8-digit confirmation code. |
54
54
  | **`after-response`** (Stop) | Touches a `.last-active` sentinel so `ccs --order-by active` can sort sessions by recency of Claude activity. |
@@ -94,7 +94,7 @@ If you've ever tried to remember which `1f4a8b3c-...` UUID is the session where
94
94
 
95
95
  - **Python 3.11+** (3.12+ recommended)
96
96
  - **The `claude` CLI on your `$PATH`.** Install it first via [the official Claude Code instructions](https://docs.anthropic.com/en/docs/claude-code/setup) and verify with `claude --version`.
97
- - **`ccusage` (optional)** - if on `$PATH`, `claude-code-usage reconcile` cross-checks dollar totals against it. Skipped gracefully if missing.
97
+ - **`ccusage` (optional)** - if on `$PATH` (or in bun's global bin dir, `~/.bun/bin`), `claude-code-usage reconcile` cross-checks dollar totals against it. Skipped gracefully if missing. Needs `bun` to install; `ccst doctor` reports both under `deps:bun` / `deps:ccusage` and prints the install command. See the `analyse-cc-usage` skill's setup section.
98
98
  - **`ripgrep` (optional)** - `ccs --contents` prefers `rg`; falls back to threaded Python `grep` if missing.
99
99
 
100
100
  ### Install and set up
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "cc-session-tools"
7
- version = "3.6.1"
7
+ version = "3.7.0"
8
8
  description = "Claude Code session management CLI tools (ccd, ccr, ccs, claude-code-usage, ccst) and hook library (hooks package)"
9
9
  readme = "README.md"
10
10
  license = { file = "LICENSE" }
@@ -6,6 +6,8 @@ Current subcommands:
6
6
  hooks install [--hook <name>] Merge hook entries from the bundled set (or a
7
7
  custom --source) into a target settings.json.
8
8
  hooks uninstall [--hook <name>] Remove hook entries from a target settings.json.
9
+ hooks allowlist list|add|remove|verify
10
+ Manage the bash-security-review reviewed-script allowlist.
9
11
  hooks run <name> Run a Claude Code hook by name.
10
12
  Available hooks: bash-hard-deny,
11
13
  bash-security-review, marker-allow,
@@ -1949,6 +1951,65 @@ def _cmd_machine_identity_confirm(args: argparse.Namespace) -> int:
1949
1951
  # ---------- hooks run ----------
1950
1952
 
1951
1953
 
1954
+ def _cmd_hooks_allowlist(args: argparse.Namespace) -> int:
1955
+ """`ccst hooks allowlist list|add|remove|verify` - the reviewed-script allowlist store."""
1956
+ import hashlib
1957
+
1958
+ from hooks import cache as cache_mod
1959
+ from hooks import script_allowlist
1960
+
1961
+ verb = args.allowlist_verb
1962
+ if verb == "list":
1963
+ entries = cache_mod.allowlist_list()
1964
+ if not entries:
1965
+ print("No allowlisted scripts.")
1966
+ return 0
1967
+ for e in entries:
1968
+ print(
1969
+ f"{e.script_path} source={e.source} sha256={e.sha256[:8]} added={e.added_at} "
1970
+ f"last_used={e.last_used or '-'} uses={e.use_count}"
1971
+ )
1972
+ return 0
1973
+ if verb == "add":
1974
+ path = Path(args.script).expanduser().resolve()
1975
+ if not path.is_file():
1976
+ print(f"error: {args.script}: not a file", file=sys.stderr)
1977
+ return 2
1978
+ root = script_allowlist.find_project_root(path.parent)
1979
+ digest = hashlib.sha256(path.read_bytes()).hexdigest()
1980
+ cache_mod.allowlist_upsert(
1981
+ str(path), digest, str(root), source="manual", overwrite_source=True
1982
+ )
1983
+ print(f"Allowlisted {path} (sha256 {digest[:8]}, project {root})")
1984
+ return 0
1985
+ if verb == "remove":
1986
+ path = Path(args.script).expanduser().resolve()
1987
+ if not cache_mod.allowlist_remove(str(path)):
1988
+ print(f"error: {path} is not in the allowlist", file=sys.stderr)
1989
+ return 1
1990
+ print(f"Removed {path}")
1991
+ return 0
1992
+ # verify
1993
+ drift = 0
1994
+ entries = cache_mod.allowlist_list()
1995
+ if not entries:
1996
+ print("No allowlisted scripts.")
1997
+ return 0
1998
+ for e in entries:
1999
+ p = Path(e.script_path)
2000
+ if not p.is_file():
2001
+ print(f"MISSING {e.script_path}")
2002
+ drift += 1
2003
+ continue
2004
+ current = hashlib.sha256(p.read_bytes()).hexdigest()
2005
+ if current != e.sha256:
2006
+ print(f"CHANGED {e.script_path} {e.sha256[:8]} -> {current[:8]}")
2007
+ drift += 1
2008
+ else:
2009
+ print(f"OK {e.script_path}")
2010
+ return 1 if drift else 0
2011
+
2012
+
1952
2013
  def _cmd_hooks_run(args: argparse.Namespace) -> int:
1953
2014
  """Dispatch to the named hook, or exit 1 (never 2) if it is unknown.
1954
2015
 
@@ -2598,6 +2659,24 @@ def _build_parser() -> argparse.ArgumentParser:
2598
2659
  help="Write changes (default: dry run)",
2599
2660
  )
2600
2661
 
2662
+ # hooks allowlist
2663
+ allowlist_parser = hooks_sub.add_parser(
2664
+ "allowlist",
2665
+ help="Manage the bash-security-review reviewed-script allowlist",
2666
+ )
2667
+ allowlist_sub = allowlist_parser.add_subparsers(dest="allowlist_verb", metavar="<action>")
2668
+ allowlist_sub.required = True
2669
+ allowlist_sub.add_parser("list", help="List allowlisted scripts")
2670
+ allowlist_add = allowlist_sub.add_parser(
2671
+ "add", help="Allowlist a script at its current content hash (you vouch for it)"
2672
+ )
2673
+ allowlist_add.add_argument("script", metavar="<script>", help="Path to the script")
2674
+ allowlist_remove = allowlist_sub.add_parser("remove", help="Remove a script from the allowlist")
2675
+ allowlist_remove.add_argument("script", metavar="<script>", help="Path to the script")
2676
+ allowlist_sub.add_parser(
2677
+ "verify", help="Report allowlisted scripts that changed or no longer exist (exit 1 on drift)"
2678
+ )
2679
+
2601
2680
  # hooks run
2602
2681
  run_parser = hooks_sub.add_parser(
2603
2682
  "run",
@@ -3500,6 +3579,8 @@ def main() -> None:
3500
3579
  sys.exit(_cmd_hooks_install(args))
3501
3580
  if args.verb == "uninstall":
3502
3581
  sys.exit(_cmd_hooks_uninstall(args))
3582
+ if args.verb == "allowlist":
3583
+ sys.exit(_cmd_hooks_allowlist(args))
3503
3584
  if args.verb == "run":
3504
3585
  sys.exit(_cmd_hooks_run(args))
3505
3586
 
@@ -0,0 +1,39 @@
1
+ """Locate tools installed through bun (bun itself, ccusage).
2
+
3
+ `bun add -g` installs into ``$BUN_INSTALL/bin`` (default ``~/.bun/bin``). That directory is
4
+ only on ``PATH`` if the user edited a shell rc file that the current shell type reads, which
5
+ non-interactive shells (hooks, scheduled jobs, subagent Bash calls) often do not. Resolving the
6
+ directory directly keeps a correct install findable from every shell type.
7
+ """
8
+ from __future__ import annotations
9
+
10
+ import dataclasses
11
+ import os
12
+ import shutil
13
+ from pathlib import Path
14
+
15
+ # Upstream's installer works on macOS and on Linux/WSL (which also needs `unzip` installed).
16
+ BUN_INSTALL_COMMAND = "curl -fsSL https://bun.sh/install | bash"
17
+ CCUSAGE_INSTALL_COMMAND = "bun add -g ccusage"
18
+
19
+
20
+ @dataclasses.dataclass(frozen=True, slots=True)
21
+ class Resolved:
22
+ path: str
23
+ on_path: bool
24
+
25
+
26
+ def bun_bin_dir() -> Path:
27
+ install = os.environ.get("BUN_INSTALL")
28
+ return (Path(install) if install else Path.home() / ".bun") / "bin"
29
+
30
+
31
+ def resolve(name: str, *, bin_dir: Path | None = None) -> Resolved | None:
32
+ """Find *name* on ``PATH`` first, then in bun's global bin directory."""
33
+ found = shutil.which(name)
34
+ if found is not None:
35
+ return Resolved(path=found, on_path=True)
36
+ candidate = (bin_dir if bin_dir is not None else bun_bin_dir()) / name
37
+ if candidate.is_file() and os.access(candidate, os.X_OK):
38
+ return Resolved(path=str(candidate), on_path=False)
39
+ return None
@@ -21,6 +21,7 @@ from enum import Enum
21
21
  from pathlib import Path
22
22
  from typing import TYPE_CHECKING, Any
23
23
 
24
+ from cc_session_tools.lib import bun_tools
24
25
  from cc_session_tools.lib.db import connect as _db_connect
25
26
  from cc_session_tools.lib.db import migration_applied as _migration_applied
26
27
  from cc_session_tools.lib.hook_registry import HOOK_VERBS, hook_name_from_command
@@ -121,6 +122,69 @@ def check_env_dir(
121
122
  return CheckResult(name=name, status=Status.OK, reason=str(p))
122
123
 
123
124
 
125
+ def _check_bun_tool(
126
+ name: str, *, install_hint: str, bin_dir: Path | None, timeout: float
127
+ ) -> CheckResult:
128
+ """WARN-only check for an optional bun-installed tool (see `bun_tools.resolve`)."""
129
+ check_name = f"deps:{name}"
130
+ resolved = bun_tools.resolve(name, bin_dir=bin_dir)
131
+ if resolved is None:
132
+ return CheckResult(name=check_name, status=Status.WARN, reason=f"{name!r} not found; {install_hint}")
133
+ if not resolved.on_path:
134
+ found_dir = Path(resolved.path).parent
135
+ return CheckResult(
136
+ name=check_name,
137
+ status=Status.WARN,
138
+ reason=(
139
+ f"installed at {resolved.path} but {found_dir} is not on PATH; add it to PATH "
140
+ f"(for non-interactive shells too: ~/.zshenv for zsh, ~/.profile for bash)"
141
+ ),
142
+ )
143
+ try:
144
+ result = subprocess.run(
145
+ [resolved.path, "--version"], capture_output=True, text=True, timeout=timeout
146
+ )
147
+ except (OSError, subprocess.TimeoutExpired) as e:
148
+ return CheckResult(
149
+ name=check_name, status=Status.WARN, reason=f"could not run {name} --version: {e}"
150
+ )
151
+ if result.returncode != 0:
152
+ return CheckResult(
153
+ name=check_name, status=Status.WARN, reason=f"{name} --version exited {result.returncode}"
154
+ )
155
+ return CheckResult(
156
+ name=check_name,
157
+ status=Status.OK,
158
+ reason=(result.stdout + result.stderr).strip().split("\n")[0],
159
+ )
160
+
161
+
162
+ def check_bun(bin_dir: Path | None = None, timeout: float = 5.0) -> CheckResult:
163
+ """WARN (never FAIL) if bun, needed to install ccusage, is missing or not on PATH."""
164
+ return _check_bun_tool(
165
+ "bun",
166
+ install_hint=(
167
+ f"install with `{bun_tools.BUN_INSTALL_COMMAND}` (macOS and Linux/WSL; "
168
+ "Linux/WSL also needs `unzip`)"
169
+ ),
170
+ bin_dir=bin_dir,
171
+ timeout=timeout,
172
+ )
173
+
174
+
175
+ def check_ccusage(bin_dir: Path | None = None, timeout: float = 5.0) -> CheckResult:
176
+ """WARN (never FAIL) if ccusage, used by `claude-code-usage reconcile`, is missing.
177
+
178
+ ccusage is optional: claude-code-usage works without it apart from `reconcile`.
179
+ """
180
+ return _check_bun_tool(
181
+ "ccusage",
182
+ install_hint=f"install bun first (see deps:bun), then `{bun_tools.CCUSAGE_INSTALL_COMMAND}`",
183
+ bin_dir=bin_dir,
184
+ timeout=timeout,
185
+ )
186
+
187
+
124
188
  def check_settings_json(settings_path: Path) -> CheckResult:
125
189
  """Verify settings.json exists and is valid JSON."""
126
190
  name = "settings.json"
@@ -1111,6 +1175,10 @@ def run_all_checks(
1111
1175
  results.extend(check_sessions_uuid_migration(sessions_db_path))
1112
1176
  results.extend(check_sessions_project_dir_absolute(sessions_db_path))
1113
1177
 
1178
+ # Optional dependencies for claude-code-usage's reconcile / ccusage blocks
1179
+ results.append(check_bun())
1180
+ results.append(check_ccusage())
1181
+
1114
1182
  # PyPI version check
1115
1183
  if not skip_pypi:
1116
1184
  results.append(check_pypi_version(installed_version))
@@ -206,8 +206,23 @@ claude-code-usage --version # should print the version
206
206
  uv sync --extra dev
207
207
  uv run pytest # all 350+ tests should pass
208
208
 
209
- # 4. Install ccusage globally so reconciliation works
210
- # Install bun first if needed: https://bun.com/docs/installation
209
+ # 4a. Install bun (needed to install ccusage). Same command on macOS and Linux/WSL.
210
+ # Linux/WSL: install `unzip` first (e.g. `sudo apt install unzip`), and install bun
211
+ # inside the Linux environment - a Windows-side bun is not visible to WSL tools.
212
+ # macOS alternative: `brew install oven-sh/bun/bun`.
213
+ curl -fsSL https://bun.sh/install | bash
214
+ bun --version
215
+
216
+ # 4b. Make bun's global bin dir (default ~/.bun/bin) resolvable on PATH, including in
217
+ # non-interactive shells (hooks, scheduled jobs). The installer edits the rc file of the
218
+ # shell you ran it from, which non-interactive shells often skip; also add it to
219
+ # ~/.zshenv (zsh) or ~/.profile (bash):
220
+ # export PATH="$HOME/.bun/bin:$PATH"
221
+ # claude-code-usage also falls back to ~/.bun/bin ($BUN_INSTALL/bin) on its own, so
222
+ # reconcile works without this; the PATH edit is what makes the `ccusage` command itself
223
+ # (e.g. `ccusage blocks`) available.
224
+
225
+ # 4c. Install ccusage globally so reconciliation works
211
226
  bun add -g ccusage
212
227
  ccusage --version
213
228
 
@@ -223,6 +238,11 @@ claude-code-usage warm-cache
223
238
  claude-code-usage reconcile
224
239
  ```
225
240
 
241
+ **Existing machine that already has CCST:** `ccst doctor` reports `deps:bun` and `deps:ccusage`
242
+ (WARN when missing or not on `PATH`, with the exact fix). `ccst install-everything` runs doctor at
243
+ its end, so upgrading surfaces a missing install; CCST never installs bun or ccusage itself. Mute
244
+ with `ccst doctor --mute deps:ccusage` if you deliberately skip it.
245
+
226
246
  The repo can also be sourced from GitHub directly (via the upstream
227
247
  remote) if you don't want to clone it - see the README's "Install"
228
248
  section for that path.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cc-session-tools
3
- Version: 3.6.1
3
+ Version: 3.7.0
4
4
  Summary: Claude Code session management CLI tools (ccd, ccr, ccs, claude-code-usage, ccst) and hook library (hooks package)
5
5
  Author: raffishquartan
6
6
  License: MIT License
@@ -105,7 +105,7 @@ bundled scheduled jobs:
105
105
  | **`session-tag`** (SessionStart) | Writes a `<uuid>.tag` file so `claude-code-usage` can map session UUIDs to human-readable names. |
106
106
  | **`last-screenshot`** (UserPromptSubmit) | Resolves your newest screenshot for the `>lss` token and injects its path. Requires `CCST_SCREENSHOT_DIR`. |
107
107
  | **`bash-hard-deny`** (PreToolUse) | Categorical hard-deny gate for Bash: destructive file ops (`rm`/`rmdir`/`unlink`/`shred`, incl. inline python/node and script-file/heredoc forms), delete-by-move to a tmp-like location, `git branch`/`git push` branch deletion, `gh api`/`gh release` delete, destructive curl/wget methods, `sudo`, and direct telemetry-log reads. Runs before every other Bash hook; a match here can never be overridden in-session (the message tells you to run the command yourself in a separate terminal). |
108
- | **`bash-security-review`** (PreToolUse) | Tiered Bash command security review with an allowlist cache and LLM fallback. |
108
+ | **`bash-security-review`** (PreToolUse) | Tiered Bash command security review: trivial/read-only pre-filters, heuristic escalation, a reviewed-script allowlist (script path + content hash, managed with `ccst hooks allowlist list\|add\|remove\|verify`), a command cache, and a slimmed `claude -p` LLM fallback (~770 tokens per review instead of ~50k+). |
109
109
  | **`marker-allow`** (PreToolUse) | Auto-approves a bare `touch` of a skill marker under `~/.cache/claude/markers/` (and nothing else), so marker-gated skills can refresh their TTL marker without a permission prompt. |
110
110
  | **`confirm-8digit`** (PreToolUse) | Blocks a configurable set of high-stakes tool calls unless the user repeats back an 8-digit confirmation code. |
111
111
  | **`after-response`** (Stop) | Touches a `.last-active` sentinel so `ccs --order-by active` can sort sessions by recency of Claude activity. |
@@ -151,7 +151,7 @@ If you've ever tried to remember which `1f4a8b3c-...` UUID is the session where
151
151
 
152
152
  - **Python 3.11+** (3.12+ recommended)
153
153
  - **The `claude` CLI on your `$PATH`.** Install it first via [the official Claude Code instructions](https://docs.anthropic.com/en/docs/claude-code/setup) and verify with `claude --version`.
154
- - **`ccusage` (optional)** - if on `$PATH`, `claude-code-usage reconcile` cross-checks dollar totals against it. Skipped gracefully if missing.
154
+ - **`ccusage` (optional)** - if on `$PATH` (or in bun's global bin dir, `~/.bun/bin`), `claude-code-usage reconcile` cross-checks dollar totals against it. Skipped gracefully if missing. Needs `bun` to install; `ccst doctor` reports both under `deps:bun` / `deps:ccusage` and prints the install command. See the `analyse-cc-usage` skill's setup section.
155
155
  - **`ripgrep` (optional)** - `ccs --contents` prefers `rg`; falls back to threaded Python `grep` if missing.
156
156
 
157
157
  ### Install and set up
@@ -23,6 +23,7 @@ src/cc_session_tools/cli/migrate_telemetry.py
23
23
  src/cc_session_tools/config/hooks-bundle.json
24
24
  src/cc_session_tools/config/session-tag-hook.json
25
25
  src/cc_session_tools/lib/__init__.py
26
+ src/cc_session_tools/lib/bun_tools.py
26
27
  src/cc_session_tools/lib/claude_flags.py
27
28
  src/cc_session_tools/lib/claude_md_install.py
28
29
  src/cc_session_tools/lib/context_overrides.py
@@ -176,6 +177,7 @@ src/hooks/normalise.py
176
177
  src/hooks/pdata_sync.py
177
178
  src/hooks/pending_migration.py
178
179
  src/hooks/pending_rename.py
180
+ src/hooks/script_allowlist.py
179
181
  src/hooks/session_tag.py
180
182
  src/hooks/stats.py
181
183
  src/hooks/telemetry.py
@@ -187,6 +189,8 @@ tests/test_after_response.py
187
189
  tests/test_attribution.py
188
190
  tests/test_bash_hard_deny.py
189
191
  tests/test_bash_security_review.py
192
+ tests/test_bash_security_review_allowlist.py
193
+ tests/test_bun_tools.py
190
194
  tests/test_cache.py
191
195
  tests/test_cache_sqlite.py
192
196
  tests/test_ccr_orphans.py
@@ -204,6 +208,7 @@ tests/test_ccst_doctor.py
204
208
  tests/test_ccst_gc_prune.py
205
209
  tests/test_ccst_gc_report.py
206
210
  tests/test_ccst_hook_dispatcher.py
211
+ tests/test_ccst_hooks_allowlist.py
207
212
  tests/test_ccst_hooks_install_prune.py
208
213
  tests/test_ccst_hooks_install_zero_arg.py
209
214
  tests/test_ccst_hooks_uninstall.py
@@ -268,6 +273,7 @@ tests/test_roots.py
268
273
  tests/test_rules.py
269
274
  tests/test_scheduler_bundled_jobs.py
270
275
  tests/test_schema.py
276
+ tests/test_script_allowlist.py
271
277
  tests/test_session_names.py
272
278
  tests/test_session_tag.py
273
279
  tests/test_sessions.py
@@ -10,11 +10,12 @@ that's our domain.
10
10
  from __future__ import annotations
11
11
 
12
12
  import json
13
- import shutil
14
13
  import subprocess
15
14
  from dataclasses import dataclass, field
16
15
  from typing import Any
17
16
 
17
+ from cc_session_tools.lib import bun_tools
18
+
18
19
 
19
20
  @dataclass
20
21
  class DailyEntry:
@@ -52,11 +53,11 @@ class ReconcileDiff:
52
53
 
53
54
 
54
55
  class CcusageNotInstalled(RuntimeError):
55
- """Raised when ccusage is not on PATH."""
56
+ """Raised when ccusage is neither on PATH nor in bun's global bin directory."""
56
57
 
57
58
 
58
59
  def is_available() -> bool:
59
- return shutil.which("ccusage") is not None
60
+ return bun_tools.resolve("ccusage") is not None
60
61
 
61
62
 
62
63
  def run_daily(since: str | None = None, until: str | None = None,
@@ -65,9 +66,14 @@ def run_daily(since: str | None = None, until: str | None = None,
65
66
 
66
67
  Dates are formatted as YYYYMMDD per ccusage's CLI.
67
68
  """
68
- if not is_available():
69
- raise CcusageNotInstalled("ccusage CLI is not on PATH; bun add -g ccusage")
70
- cmd = ["ccusage", "daily", "--json"]
69
+ resolved = bun_tools.resolve("ccusage")
70
+ if resolved is None:
71
+ raise CcusageNotInstalled(
72
+ "ccusage not found on PATH or in bun's global bin directory. Follow the "
73
+ "analyse-cc-usage skill's setup step 4 (install bun, then "
74
+ f"`{bun_tools.CCUSAGE_INSTALL_COMMAND}`); `ccst doctor` shows the current state."
75
+ )
76
+ cmd = [resolved.path, "daily", "--json"]
71
77
  if offline:
72
78
  cmd.append("--offline")
73
79
  if since: