cc-session-tools 3.10.2__tar.gz → 3.10.3__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 (300) hide show
  1. {cc_session_tools-3.10.2/src/cc_session_tools.egg-info → cc_session_tools-3.10.3}/PKG-INFO +1 -1
  2. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/pyproject.toml +1 -1
  3. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/cc_session_tools/skills/pm-pdata-do-init/SKILL.md +3 -0
  4. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3/src/cc_session_tools.egg-info}/PKG-INFO +1 -1
  5. cc_session_tools-3.10.3/src/claude_code_usage/data/pricing.json +181 -0
  6. cc_session_tools-3.10.3/src/claude_code_usage/pricing.py +134 -0
  7. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/hooks/context_window_warning.py +21 -15
  8. cc_session_tools-3.10.3/src/hooks/model_info.py +78 -0
  9. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/tests/test_context_window_warning.py +63 -16
  10. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/tests/test_model_info.py +17 -15
  11. cc_session_tools-3.10.3/tests/test_pricing.py +189 -0
  12. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/tests/test_query.py +4 -4
  13. cc_session_tools-3.10.2/src/claude_code_usage/data/pricing.json +0 -102
  14. cc_session_tools-3.10.2/src/claude_code_usage/pricing.py +0 -97
  15. cc_session_tools-3.10.2/src/hooks/model_info.py +0 -79
  16. cc_session_tools-3.10.2/tests/test_pricing.py +0 -70
  17. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/LICENSE +0 -0
  18. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/README.md +0 -0
  19. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/setup.cfg +0 -0
  20. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/cc_session_tools/__init__.py +0 -0
  21. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/cc_session_tools/cli/__init__.py +0 -0
  22. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/cc_session_tools/cli/ccd.py +0 -0
  23. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/cc_session_tools/cli/ccmsg.py +0 -0
  24. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/cc_session_tools/cli/ccr.py +0 -0
  25. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/cc_session_tools/cli/ccs.py +0 -0
  26. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/cc_session_tools/cli/ccsched.py +0 -0
  27. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/cc_session_tools/cli/ccst.py +0 -0
  28. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/cc_session_tools/cli/migrate_ccmsg.py +0 -0
  29. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/cc_session_tools/cli/migrate_ccsched.py +0 -0
  30. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/cc_session_tools/cli/migrate_sessions_db.py +0 -0
  31. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/cc_session_tools/cli/migrate_telemetry.py +0 -0
  32. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/cc_session_tools/config/hooks-bundle.json +0 -0
  33. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/cc_session_tools/config/session-tag-hook.json +0 -0
  34. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/cc_session_tools/hooks_install.py +0 -0
  35. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/cc_session_tools/lib/__init__.py +0 -0
  36. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/cc_session_tools/lib/bun_tools.py +0 -0
  37. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/cc_session_tools/lib/claude_flags.py +0 -0
  38. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/cc_session_tools/lib/claude_md_install.py +0 -0
  39. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/cc_session_tools/lib/context_overrides.py +0 -0
  40. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/cc_session_tools/lib/db.py +0 -0
  41. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/cc_session_tools/lib/debug.py +0 -0
  42. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/cc_session_tools/lib/doctor.py +0 -0
  43. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/cc_session_tools/lib/doctor_mutes.py +0 -0
  44. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/cc_session_tools/lib/hook_registry.py +0 -0
  45. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/cc_session_tools/lib/install_sync.py +0 -0
  46. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/cc_session_tools/lib/levenshtein.py +0 -0
  47. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/cc_session_tools/lib/machine_identity.py +0 -0
  48. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/cc_session_tools/lib/messaging/__init__.py +0 -0
  49. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/cc_session_tools/lib/messaging/addressing.py +0 -0
  50. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/cc_session_tools/lib/messaging/cursor.py +0 -0
  51. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/cc_session_tools/lib/messaging/lock.py +0 -0
  52. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/cc_session_tools/lib/messaging/message.py +0 -0
  53. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/cc_session_tools/lib/messaging/move_safety.py +0 -0
  54. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/cc_session_tools/lib/messaging/repository.py +0 -0
  55. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/cc_session_tools/lib/messaging/retention.py +0 -0
  56. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/cc_session_tools/lib/messaging/service.py +0 -0
  57. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/cc_session_tools/lib/messaging/store.py +0 -0
  58. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/cc_session_tools/lib/occupancy.py +0 -0
  59. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/cc_session_tools/lib/paths.py +0 -0
  60. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/cc_session_tools/lib/pdata/__init__.py +0 -0
  61. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/cc_session_tools/lib/pdata/backup.py +0 -0
  62. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/cc_session_tools/lib/pdata/classify.py +0 -0
  63. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/cc_session_tools/lib/pdata/cutover.py +0 -0
  64. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/cc_session_tools/lib/pdata/dump.py +0 -0
  65. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/cc_session_tools/lib/pdata/formatting.py +0 -0
  66. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/cc_session_tools/lib/pdata/importers.py +0 -0
  67. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/cc_session_tools/lib/pdata/init_paths.py +0 -0
  68. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/cc_session_tools/lib/pdata/init_service.py +0 -0
  69. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/cc_session_tools/lib/pdata/manifest.py +0 -0
  70. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/cc_session_tools/lib/pdata/naming.py +0 -0
  71. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/cc_session_tools/lib/pdata/readiness.py +0 -0
  72. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/cc_session_tools/lib/pdata/rehydrate.py +0 -0
  73. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/cc_session_tools/lib/pdata/rename_group.py +0 -0
  74. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/cc_session_tools/lib/pdata/reorganize.py +0 -0
  75. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/cc_session_tools/lib/pdata/repository.py +0 -0
  76. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/cc_session_tools/lib/pdata/resolve.py +0 -0
  77. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/cc_session_tools/lib/pdata/service.py +0 -0
  78. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/cc_session_tools/lib/pdata/session_output.py +0 -0
  79. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/cc_session_tools/lib/pdata/store.py +0 -0
  80. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/cc_session_tools/lib/pdata/sync_check.py +0 -0
  81. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/cc_session_tools/lib/pdata/sync_lock.py +0 -0
  82. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/cc_session_tools/lib/pdata/sync_notify.py +0 -0
  83. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/cc_session_tools/lib/pdata/vector_clock.py +0 -0
  84. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/cc_session_tools/lib/pdata/vector_clock_store.py +0 -0
  85. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/cc_session_tools/lib/pdata/verify.py +0 -0
  86. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/cc_session_tools/lib/pdata/write_log.py +0 -0
  87. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/cc_session_tools/lib/picker.py +0 -0
  88. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/cc_session_tools/lib/proc_lock.py +0 -0
  89. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/cc_session_tools/lib/prompts.py +0 -0
  90. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/cc_session_tools/lib/roots.py +0 -0
  91. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/cc_session_tools/lib/rules.py +0 -0
  92. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/cc_session_tools/lib/scheduler/__init__.py +0 -0
  93. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/cc_session_tools/lib/scheduler/bundled_jobs.py +0 -0
  94. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/cc_session_tools/lib/scheduler/cadence.py +0 -0
  95. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/cc_session_tools/lib/scheduler/cursor.py +0 -0
  96. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/cc_session_tools/lib/scheduler/digest.py +0 -0
  97. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/cc_session_tools/lib/scheduler/due.py +0 -0
  98. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/cc_session_tools/lib/scheduler/duration.py +0 -0
  99. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/cc_session_tools/lib/scheduler/jobspec.py +0 -0
  100. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/cc_session_tools/lib/scheduler/ledger.py +0 -0
  101. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/cc_session_tools/lib/scheduler/lock.py +0 -0
  102. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/cc_session_tools/lib/scheduler/notify.py +0 -0
  103. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/cc_session_tools/lib/scheduler/reconcile.py +0 -0
  104. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/cc_session_tools/lib/scheduler/registry.py +0 -0
  105. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/cc_session_tools/lib/scheduler/runner.py +0 -0
  106. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/cc_session_tools/lib/scheduler/state.py +0 -0
  107. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/cc_session_tools/lib/scheduler/store.py +0 -0
  108. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/cc_session_tools/lib/scheduler/surface.py +0 -0
  109. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/cc_session_tools/lib/scheduler/throttle.py +0 -0
  110. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/cc_session_tools/lib/scheduler/worker.py +0 -0
  111. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/cc_session_tools/lib/session_gc.py +0 -0
  112. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/cc_session_tools/lib/sessions.py +0 -0
  113. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/cc_session_tools/lib/sessions_db.py +0 -0
  114. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/cc_session_tools/lib/sessions_repair.py +0 -0
  115. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/cc_session_tools/lib/shell_install.py +0 -0
  116. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/cc_session_tools/lib/tasklist.py +0 -0
  117. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/cc_session_tools/lib/telemetry_store.py +0 -0
  118. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/cc_session_tools/lib/text_wrap.py +0 -0
  119. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/cc_session_tools/skills/analyse-cc-usage/SKILL.md +0 -0
  120. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/cc_session_tools/skills/clean-hook-sessions/SKILL.md +0 -0
  121. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/cc_session_tools/skills/clean-hook-sessions/scripts/clean-hook-sessions.py +0 -0
  122. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/cc_session_tools/skills/compact-smart/SKILL.md +0 -0
  123. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/cc_session_tools/skills/context-override/SKILL.md +0 -0
  124. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/cc_session_tools/skills/delete-sessions/SKILL.md +0 -0
  125. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/cc_session_tools/skills/delete-sessions/scripts/delete_sessions.py +0 -0
  126. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/cc_session_tools/skills/do-executor-critic-assessor-loop/SKILL.md +0 -0
  127. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/cc_session_tools/skills/extract-pptx/SKILL.md +0 -0
  128. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/cc_session_tools/skills/extract-pptx/scripts/extract_pptx.py +0 -0
  129. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/cc_session_tools/skills/extract-to-text/SKILL.md +0 -0
  130. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/cc_session_tools/skills/extract-to-text/scripts/extract_to_text.py +0 -0
  131. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/cc_session_tools/skills/find-claude-code-session/SKILL.md +0 -0
  132. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/cc_session_tools/skills/generate-8digit-code/SKILL.md +0 -0
  133. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/cc_session_tools/skills/generate-8digit-code/scripts/generate_8digit_code.py +0 -0
  134. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/cc_session_tools/skills/list-empty-sessions/SKILL.md +0 -0
  135. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/cc_session_tools/skills/list-empty-sessions/scripts/list_empty_sessions.py +0 -0
  136. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/cc_session_tools/skills/manage-recurring-cc-jobs-using-ccsched/SKILL.md +0 -0
  137. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/cc_session_tools/skills/move-session/SKILL.md +0 -0
  138. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/cc_session_tools/skills/move-session/hooks/sessionstart-pending-rename.sh +0 -0
  139. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/cc_session_tools/skills/move-session/scripts/cc_session_rules.py +0 -0
  140. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/cc_session_tools/skills/move-session/scripts/move_session.py +0 -0
  141. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/cc_session_tools/skills/pm-pdata-design-schema/SKILL.md +0 -0
  142. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/cc_session_tools/skills/pm-pdata-do-audit-and-prepare-to-migrate/SKILL.md +0 -0
  143. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/cc_session_tools/skills/pm-pdata-do-manual-migration/SKILL.md +0 -0
  144. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/cc_session_tools/skills/pm-pdata-do-update-consuming-skills/SKILL.md +0 -0
  145. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/cc_session_tools/skills/pm-pdata-do-update-project-docs/SKILL.md +0 -0
  146. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/cc_session_tools/skills/pm-pdata-resolve-conflicts/SKILL.md +0 -0
  147. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/cc_session_tools/skills/pm-project-layout-reference/SKILL.md +0 -0
  148. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/cc_session_tools/skills/pm-update-central-files/SKILL.md +0 -0
  149. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/cc_session_tools/skills/reduce-persistent-context/CALIBRATION.md +0 -0
  150. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/cc_session_tools/skills/reduce-persistent-context/SKILL.md +0 -0
  151. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/cc_session_tools/skills/reduce-persistent-context/scripts/analyze_context.py +0 -0
  152. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/cc_session_tools/skills/reduce-persistent-context/scripts/duplicates.py +0 -0
  153. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/cc_session_tools/skills/reduce-persistent-context/scripts/measure.py +0 -0
  154. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/cc_session_tools/skills/reduce-persistent-context/scripts/report.py +0 -0
  155. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/cc_session_tools/skills/reduce-persistent-context/scripts/tokens.py +0 -0
  156. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/cc_session_tools/skills/reduce-persistent-context/scripts/usage.py +0 -0
  157. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/cc_session_tools/skills/select-agent-model/SKILL.md +0 -0
  158. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/cc_session_tools/skills/send-session-message/SKILL.md +0 -0
  159. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/cc_session_tools/skills/update-command-cache/SKILL.md +0 -0
  160. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/cc_session_tools/skills/update-command-cache/scripts/update_command_cache.py +0 -0
  161. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/cc_session_tools.egg-info/SOURCES.txt +0 -0
  162. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/cc_session_tools.egg-info/dependency_links.txt +0 -0
  163. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/cc_session_tools.egg-info/entry_points.txt +0 -0
  164. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/cc_session_tools.egg-info/requires.txt +0 -0
  165. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/cc_session_tools.egg-info/top_level.txt +0 -0
  166. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/claude_code_usage/__init__.py +0 -0
  167. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/claude_code_usage/attribution.py +0 -0
  168. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/claude_code_usage/cache.py +0 -0
  169. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/claude_code_usage/ccusage_wrapper.py +0 -0
  170. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/claude_code_usage/cli.py +0 -0
  171. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/claude_code_usage/parent_inference.py +0 -0
  172. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/claude_code_usage/parser.py +0 -0
  173. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/claude_code_usage/query.py +0 -0
  174. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/claude_code_usage/report.py +0 -0
  175. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/claude_code_usage/schema.py +0 -0
  176. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/claude_code_usage/session_names.py +0 -0
  177. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/hooks/__init__.py +0 -0
  178. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/hooks/after_response.py +0 -0
  179. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/hooks/bash_hard_deny.py +0 -0
  180. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/hooks/bash_security_review.py +0 -0
  181. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/hooks/cache.py +0 -0
  182. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/hooks/catchup.py +0 -0
  183. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/hooks/confirm_8digit.py +0 -0
  184. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/hooks/last_screenshot.py +0 -0
  185. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/hooks/marker_allow.py +0 -0
  186. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/hooks/markers.py +0 -0
  187. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/hooks/messaging_deliver.py +0 -0
  188. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/hooks/normalise.py +0 -0
  189. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/hooks/pdata_sync.py +0 -0
  190. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/hooks/pending_migration.py +0 -0
  191. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/hooks/pending_rename.py +0 -0
  192. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/hooks/script_allowlist.py +0 -0
  193. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/hooks/session_tag.py +0 -0
  194. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/hooks/stats.py +0 -0
  195. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/hooks/telemetry.py +0 -0
  196. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/hooks/telemetry_query.py +0 -0
  197. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/hooks/telemetry_trim.py +0 -0
  198. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/hooks/transcript.py +0 -0
  199. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/src/hooks/worklog_guard.py +0 -0
  200. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/tests/test_after_response.py +0 -0
  201. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/tests/test_attribution.py +0 -0
  202. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/tests/test_bash_hard_deny.py +0 -0
  203. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/tests/test_bash_security_review.py +0 -0
  204. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/tests/test_bash_security_review_allowlist.py +0 -0
  205. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/tests/test_bun_tools.py +0 -0
  206. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/tests/test_cache.py +0 -0
  207. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/tests/test_cache_sqlite.py +0 -0
  208. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/tests/test_ccr_orphans.py +0 -0
  209. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/tests/test_ccs_emptiness.py +0 -0
  210. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/tests/test_ccs_eta.py +0 -0
  211. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/tests/test_ccs_list_mode.py +0 -0
  212. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/tests/test_ccs_scope_flags.py +0 -0
  213. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/tests/test_ccs_sentinel_sort.py +0 -0
  214. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/tests/test_ccs_session_counts.py +0 -0
  215. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/tests/test_ccst_bundle_discovery.py +0 -0
  216. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/tests/test_ccst_ccsched_jobs_cli.py +0 -0
  217. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/tests/test_ccst_cli.py +0 -0
  218. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/tests/test_ccst_context_override_cli.py +0 -0
  219. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/tests/test_ccst_doctor.py +0 -0
  220. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/tests/test_ccst_gc_prune.py +0 -0
  221. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/tests/test_ccst_gc_report.py +0 -0
  222. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/tests/test_ccst_hook_dispatcher.py +0 -0
  223. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/tests/test_ccst_hooks_allowlist.py +0 -0
  224. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/tests/test_ccst_hooks_install_prune.py +0 -0
  225. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/tests/test_ccst_hooks_install_zero_arg.py +0 -0
  226. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/tests/test_ccst_hooks_uninstall.py +0 -0
  227. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/tests/test_ccst_install_everything.py +0 -0
  228. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/tests/test_ccst_machine_identity_cli.py +0 -0
  229. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/tests/test_ccst_main_gate.py +0 -0
  230. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/tests/test_ccst_pdata_cli.py +0 -0
  231. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/tests/test_ccst_pdata_init_cli.py +0 -0
  232. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/tests/test_ccst_pdata_readiness_cli.py +0 -0
  233. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/tests/test_ccst_pdata_reconcile_cli.py +0 -0
  234. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/tests/test_ccst_pdata_rename_group_cli.py +0 -0
  235. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/tests/test_ccst_pdata_reorganize_cli.py +0 -0
  236. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/tests/test_ccst_pdata_sync_cli.py +0 -0
  237. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/tests/test_ccst_pdata_verify_cli.py +0 -0
  238. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/tests/test_ccst_repair_sessions_cli.py +0 -0
  239. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/tests/test_ccst_sessions_cli.py +0 -0
  240. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/tests/test_ccst_shell_install.py +0 -0
  241. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/tests/test_ccst_skills_install.py +0 -0
  242. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/tests/test_ccst_skills_uninstall.py +0 -0
  243. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/tests/test_ccst_telemetry_query.py +0 -0
  244. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/tests/test_ccst_telemetry_trim.py +0 -0
  245. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/tests/test_ccusage_wrapper.py +0 -0
  246. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/tests/test_claude_flags.py +0 -0
  247. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/tests/test_claude_md_install.py +0 -0
  248. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/tests/test_cli.py +0 -0
  249. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/tests/test_cli_ccd.py +0 -0
  250. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/tests/test_cli_ccd_dry_run.py +0 -0
  251. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/tests/test_cli_ccr.py +0 -0
  252. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/tests/test_cli_ccs.py +0 -0
  253. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/tests/test_cli_version.py +0 -0
  254. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/tests/test_confirm_8digit.py +0 -0
  255. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/tests/test_context_overrides.py +0 -0
  256. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/tests/test_db.py +0 -0
  257. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/tests/test_debug.py +0 -0
  258. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/tests/test_doctor_mutes.py +0 -0
  259. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/tests/test_empty_session.py +0 -0
  260. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/tests/test_hook_cache.py +0 -0
  261. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/tests/test_hooks_install.py +0 -0
  262. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/tests/test_hooks_install_records.py +0 -0
  263. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/tests/test_install_sync.py +0 -0
  264. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/tests/test_last_screenshot.py +0 -0
  265. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/tests/test_levenshtein.py +0 -0
  266. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/tests/test_machine_identity.py +0 -0
  267. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/tests/test_marker_allow.py +0 -0
  268. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/tests/test_migrate_ccmsg.py +0 -0
  269. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/tests/test_migrate_ccsched.py +0 -0
  270. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/tests/test_migrate_sessions_db.py +0 -0
  271. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/tests/test_migrate_telemetry.py +0 -0
  272. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/tests/test_normalise.py +0 -0
  273. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/tests/test_occupancy.py +0 -0
  274. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/tests/test_parent_inference.py +0 -0
  275. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/tests/test_parser.py +0 -0
  276. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/tests/test_paths.py +0 -0
  277. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/tests/test_pdata_audit_skill.py +0 -0
  278. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/tests/test_pdata_post_migration_skills.py +0 -0
  279. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/tests/test_pending_migration_hook.py +0 -0
  280. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/tests/test_picker.py +0 -0
  281. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/tests/test_proc_lock.py +0 -0
  282. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/tests/test_prompts.py +0 -0
  283. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/tests/test_report.py +0 -0
  284. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/tests/test_roots.py +0 -0
  285. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/tests/test_rules.py +0 -0
  286. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/tests/test_scheduler_bundled_jobs.py +0 -0
  287. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/tests/test_schema.py +0 -0
  288. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/tests/test_script_allowlist.py +0 -0
  289. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/tests/test_session_names.py +0 -0
  290. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/tests/test_session_tag.py +0 -0
  291. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/tests/test_sessions.py +0 -0
  292. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/tests/test_sessions_db.py +0 -0
  293. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/tests/test_sessions_db_migration_chain.py +0 -0
  294. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/tests/test_sessions_repair.py +0 -0
  295. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/tests/test_tasklist.py +0 -0
  296. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/tests/test_telemetry.py +0 -0
  297. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/tests/test_telemetry_store.py +0 -0
  298. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/tests/test_text_wrap.py +0 -0
  299. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/tests/test_transcript.py +0 -0
  300. {cc_session_tools-3.10.2 → cc_session_tools-3.10.3}/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.10.2
3
+ Version: 3.10.3
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
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "cc-session-tools"
7
- version = "3.10.2"
7
+ version = "3.10.3"
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" }
@@ -141,6 +141,9 @@ relative to a subfolder rather than the project root (e.g. an index-of-a-subfold
141
141
  root) - `--write`'s file_path-resolution verification will fail with a bare "does not resolve
142
142
  under `<project_root>`" and no further guidance. Instead, map that column to a plain named field
143
143
  (e.g. `source_file_path`) and note in the field's `description` what path it's relative to.
144
+ Likewise, a column documented to use multiple or shorthand path notations (e.g. brace expansion
145
+ alongside plain paths) is unsafe to map to `file_path_column` at all - map it to a plain named TEXT
146
+ field instead, exactly as for the subfolder-relative case.
144
147
 
145
148
  **`content_column: null` default caveat:** an entry with `content_column` left unset falls back to
146
149
  a raw `json.dumps(row)` dump as every record's content - rarely what you want for readable `ccst
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cc-session-tools
3
- Version: 3.10.2
3
+ Version: 3.10.3
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
@@ -0,0 +1,181 @@
1
+ {
2
+ "_source": "Anthropic published first-party API pricing (https://platform.claude.com/docs/en/about-claude/pricing), hand-curated. Per-token USD. Rows for retired models not on that page keep their historical list price.",
3
+ "_refreshed_at": "2026-09-29",
4
+ "models": {
5
+ "<synthetic>": {
6
+ "input": 0.0,
7
+ "output": 0.0,
8
+ "cache_creation_5m": 0.0,
9
+ "cache_creation_1h": 0.0,
10
+ "cache_read": 0.0
11
+ },
12
+ "claude-fable-5-1": {
13
+ "input": 0.00001,
14
+ "output": 0.00005,
15
+ "cache_creation_5m": 0.0000125,
16
+ "cache_creation_1h": 0.00002,
17
+ "cache_read": 0.00000025
18
+ },
19
+ "claude-mythos-5-1": {
20
+ "input": 0.00001,
21
+ "output": 0.00005,
22
+ "cache_creation_5m": 0.0000125,
23
+ "cache_creation_1h": 0.00002,
24
+ "cache_read": 0.00000025
25
+ },
26
+ "claude-fable-5": {
27
+ "input": 0.00001,
28
+ "output": 0.00005,
29
+ "cache_creation_5m": 0.0000125,
30
+ "cache_creation_1h": 0.00002,
31
+ "cache_read": 0.000001
32
+ },
33
+ "claude-mythos-5": {
34
+ "input": 0.00001,
35
+ "output": 0.00005,
36
+ "cache_creation_5m": 0.0000125,
37
+ "cache_creation_1h": 0.00002,
38
+ "cache_read": 0.000001
39
+ },
40
+ "claude-opus-5-5": {
41
+ "input": 0.000004,
42
+ "output": 0.00002,
43
+ "cache_creation_5m": 0.000005,
44
+ "cache_creation_1h": 0.000008,
45
+ "cache_read": 0.0000002
46
+ },
47
+ "claude-opus-5": {
48
+ "input": 0.000005,
49
+ "output": 0.000025,
50
+ "cache_creation_5m": 0.00000625,
51
+ "cache_creation_1h": 0.00001,
52
+ "cache_read": 0.0000005
53
+ },
54
+ "claude-opus-4-8": {
55
+ "input": 0.000005,
56
+ "output": 0.000025,
57
+ "cache_creation_5m": 0.00000625,
58
+ "cache_creation_1h": 0.00001,
59
+ "cache_read": 0.0000005
60
+ },
61
+ "claude-opus-4-7": {
62
+ "input": 0.000005,
63
+ "output": 0.000025,
64
+ "cache_creation_5m": 0.00000625,
65
+ "cache_creation_1h": 0.00001,
66
+ "cache_read": 0.0000005
67
+ },
68
+ "claude-opus-4-6": {
69
+ "input": 0.000005,
70
+ "output": 0.000025,
71
+ "cache_creation_5m": 0.00000625,
72
+ "cache_creation_1h": 0.00001,
73
+ "cache_read": 0.0000005
74
+ },
75
+ "claude-opus-4-5": {
76
+ "input": 0.000005,
77
+ "output": 0.000025,
78
+ "cache_creation_5m": 0.00000625,
79
+ "cache_creation_1h": 0.00001,
80
+ "cache_read": 0.0000005
81
+ },
82
+ "claude-opus-4-1": {
83
+ "input": 0.000015,
84
+ "output": 0.000075,
85
+ "cache_creation_5m": 0.00001875,
86
+ "cache_creation_1h": 0.00003,
87
+ "cache_read": 0.0000015
88
+ },
89
+ "claude-opus-4": {
90
+ "input": 0.000015,
91
+ "output": 0.000075,
92
+ "cache_creation_5m": 0.00001875,
93
+ "cache_creation_1h": 0.00003,
94
+ "cache_read": 0.0000015
95
+ },
96
+ "claude-sonnet-5-5": {
97
+ "input": 0.000002,
98
+ "output": 0.00001,
99
+ "cache_creation_5m": 0.0000025,
100
+ "cache_creation_1h": 0.000004,
101
+ "cache_read": 0.0000002
102
+ },
103
+ "claude-sonnet-5": {
104
+ "input": 0.000002,
105
+ "output": 0.00001,
106
+ "cache_creation_5m": 0.0000025,
107
+ "cache_creation_1h": 0.000004,
108
+ "cache_read": 0.0000002
109
+ },
110
+ "claude-sonnet-4-6": {
111
+ "input": 0.000003,
112
+ "output": 0.000015,
113
+ "cache_creation_5m": 0.00000375,
114
+ "cache_creation_1h": 0.000006,
115
+ "cache_read": 0.0000003
116
+ },
117
+ "claude-sonnet-4-5": {
118
+ "input": 0.000003,
119
+ "output": 0.000015,
120
+ "cache_creation_5m": 0.00000375,
121
+ "cache_creation_1h": 0.000006,
122
+ "cache_read": 0.0000003
123
+ },
124
+ "claude-sonnet-4": {
125
+ "input": 0.000003,
126
+ "output": 0.000015,
127
+ "cache_creation_5m": 0.00000375,
128
+ "cache_creation_1h": 0.000006,
129
+ "cache_read": 0.0000003
130
+ },
131
+ "claude-haiku-4-5": {
132
+ "input": 0.000001,
133
+ "output": 0.000005,
134
+ "cache_creation_5m": 0.00000125,
135
+ "cache_creation_1h": 0.000002,
136
+ "cache_read": 0.0000001
137
+ },
138
+ "claude-haiku-4": {
139
+ "input": 0.0000008,
140
+ "output": 0.000004,
141
+ "cache_creation_5m": 0.000001,
142
+ "cache_creation_1h": 0.0000016,
143
+ "cache_read": 0.00000008
144
+ },
145
+ "claude-3-7-sonnet-20250219": {
146
+ "input": 0.000003,
147
+ "output": 0.000015,
148
+ "cache_creation_5m": 0.00000375,
149
+ "cache_creation_1h": 0.000006,
150
+ "cache_read": 0.0000003
151
+ },
152
+ "claude-3-5-sonnet-20241022": {
153
+ "input": 0.000003,
154
+ "output": 0.000015,
155
+ "cache_creation_5m": 0.00000375,
156
+ "cache_creation_1h": 0.000006,
157
+ "cache_read": 0.0000003
158
+ },
159
+ "claude-3-5-haiku-20241022": {
160
+ "input": 0.0000008,
161
+ "output": 0.000004,
162
+ "cache_creation_5m": 0.000001,
163
+ "cache_creation_1h": 0.0000016,
164
+ "cache_read": 0.00000008
165
+ },
166
+ "claude-3-opus-20240229": {
167
+ "input": 0.000015,
168
+ "output": 0.000075,
169
+ "cache_creation_5m": 0.00001875,
170
+ "cache_creation_1h": 0.00003,
171
+ "cache_read": 0.0000015
172
+ }
173
+ },
174
+ "family_fallbacks": {
175
+ "fable": "claude-fable-5-1",
176
+ "mythos": "claude-mythos-5-1",
177
+ "opus": "claude-opus-5-5",
178
+ "sonnet": "claude-sonnet-5-5",
179
+ "haiku": "claude-haiku-4-5"
180
+ }
181
+ }
@@ -0,0 +1,134 @@
1
+ """Per-token pricing data and dollar calculations.
2
+
3
+ `data/pricing.json` is a hand-curated copy of Anthropic's published
4
+ first-party API rates (its `_source` / `_refreshed_at` fields say where
5
+ from and when); re-check it whenever a new model ships. Resolution order
6
+ for a model id:
7
+
8
+ 1. an exact row;
9
+ 2. a dated snapshot (`<id>-YYYYMMDD`, exactly eight digits, stripped
10
+ once) resolves to the undated row;
11
+ 3. an id containing `claude-<family>-` for a family in `family_fallbacks`
12
+ is priced as that family's newest model - an estimate, which
13
+ `add_cost_column()` reports in a warning. Claude 3 ids (`claude-3-...`)
14
+ and non-Claude ids never match, so an unlisted old model is reported as
15
+ unpriced rather than given a newer model's price;
16
+ 4. otherwise `lookup()` raises `KeyError`.
17
+
18
+ `<synthetic>` (Claude Code's zero-usage stub entries) has an explicit
19
+ all-zero row.
20
+ """
21
+
22
+ from __future__ import annotations
23
+
24
+ import json
25
+ import logging
26
+ import re
27
+ from pathlib import Path
28
+ from typing import Any
29
+
30
+ import pandas as pd
31
+
32
+ _THIS_DIR = Path(__file__).resolve().parent
33
+ _PRICING_PATH = _THIS_DIR / "data" / "pricing.json"
34
+ _DATED_SNAPSHOT = re.compile(r"(.+)-\d{8}")
35
+
36
+ logger = logging.getLogger(__name__)
37
+
38
+
39
+ def _load() -> dict[str, Any]:
40
+ return json.loads(_PRICING_PATH.read_text())
41
+
42
+
43
+ def resolve(model: str) -> tuple[str, bool]:
44
+ """Return (pricing row key, True if the row came from a family fallback).
45
+ Raises KeyError if `model` has no row and no family match."""
46
+ data = _load()
47
+ models = data["models"]
48
+ if model in models:
49
+ return model, False
50
+ dated = _DATED_SNAPSHOT.fullmatch(model)
51
+ if dated and dated.group(1) in models:
52
+ return dated.group(1), False
53
+ for family, fallback_model in data["family_fallbacks"].items():
54
+ if f"claude-{family}-" in model:
55
+ return fallback_model, True
56
+ raise KeyError(model)
57
+
58
+
59
+ def lookup(model: str) -> dict[str, float]:
60
+ """Return per-token rates for `model`. Raises KeyError if unknown."""
61
+ row, _ = resolve(model)
62
+ rates: dict[str, float] = _load()["models"][row]
63
+ return rates
64
+
65
+
66
+ def cost_for_usage(
67
+ model: str,
68
+ input_tokens: int,
69
+ output_tokens: int,
70
+ cache_creation_5m: int = 0,
71
+ cache_creation_1h: int = 0,
72
+ cache_read: int = 0,
73
+ ) -> float:
74
+ """Return the dollar cost of one assistant message's token mix."""
75
+ rates = lookup(model)
76
+ return (
77
+ input_tokens * rates["input"]
78
+ + output_tokens * rates["output"]
79
+ + cache_creation_5m * rates["cache_creation_5m"]
80
+ + cache_creation_1h * rates["cache_creation_1h"]
81
+ + cache_read * rates["cache_read"]
82
+ )
83
+
84
+
85
+ def add_cost_column(df: pd.DataFrame) -> pd.DataFrame:
86
+ """Return `df` with a `cost_usd` column added.
87
+
88
+ Vectorised over rows: builds a per-row rates frame from the model
89
+ column then dot-products against the token columns. Models that
90
+ can't be resolved (after family fallback) get cost = 0 with a
91
+ warning - we don't want a single unknown model to break a report.
92
+ Models priced by family fallback are named in a separate warning, so
93
+ an estimated price is never silent.
94
+ """
95
+ out = df.copy()
96
+ if out.empty:
97
+ out["cost_usd"] = pd.Series(dtype=float)
98
+ return out
99
+ models = _load()["models"]
100
+ zero = {"input": 0.0, "output": 0.0, "cache_creation_5m": 0.0,
101
+ "cache_creation_1h": 0.0, "cache_read": 0.0}
102
+ rates_by_model: dict[str, dict[str, float]] = {}
103
+ unknown: set[str] = set()
104
+ fallback: dict[str, str] = {}
105
+ for model in out["model"].unique():
106
+ try:
107
+ row, is_fallback = resolve(model)
108
+ except KeyError:
109
+ unknown.add(model)
110
+ rates_by_model[model] = zero
111
+ continue
112
+ rates_by_model[model] = models[row]
113
+ if is_fallback:
114
+ fallback[model] = row
115
+ rates_records = [rates_by_model[model] for model in out["model"]]
116
+ rates_df = pd.DataFrame(rates_records, index=out.index)
117
+ out["cost_usd"] = (
118
+ out["input_tokens"] * rates_df["input"]
119
+ + out["output_tokens"] * rates_df["output"]
120
+ + out["cache_creation_5m"] * rates_df["cache_creation_5m"]
121
+ + out["cache_creation_1h"] * rates_df["cache_creation_1h"]
122
+ + out["cache_read"] * rates_df["cache_read"]
123
+ )
124
+ if unknown:
125
+ logger.warning(
126
+ "no pricing for models: %s (cost set to 0 for those rows)",
127
+ sorted(unknown),
128
+ )
129
+ if fallback:
130
+ logger.warning(
131
+ "no exact pricing for models, priced by family fallback: %s",
132
+ ", ".join(f"{model} as {row}" for model, row in sorted(fallback.items())),
133
+ )
134
+ return out
@@ -41,10 +41,16 @@ class TranscriptError(Exception):
41
41
  not a single parseable JSON line."""
42
42
 
43
43
 
44
+ SYNTHETIC_MODEL = "<synthetic>"
45
+
46
+
44
47
  def _current_context_tokens(transcript_path: Path) -> tuple[int, str]:
45
48
  """(token count, model id) from the last non-sidechain assistant message's
46
49
  usage. (0, "") for a fresh session with no assistant usage yet - that is a
47
- legitimate state, not an error."""
50
+ legitimate state, not an error. Entries whose model is `<synthetic>` are
51
+ skipped: Claude Code writes them (with all-zero usage) for things that are
52
+ not API responses, such as a usage-limit notice, so they say nothing about
53
+ the context size."""
48
54
  if not transcript_path.is_file():
49
55
  raise TranscriptError(f"transcript not found: {transcript_path}")
50
56
 
@@ -68,9 +74,10 @@ def _current_context_tokens(transcript_path: Path) -> tuple[int, str]:
68
74
  continue
69
75
  message = obj.get("message") or {}
70
76
  usage = message.get("usage")
71
- if isinstance(usage, dict):
77
+ model = message.get("model") or ""
78
+ if isinstance(usage, dict) and model != SYNTHETIC_MODEL:
72
79
  last_usage = usage
73
- last_model = message.get("model") or ""
80
+ last_model = model
74
81
  except OSError as exc:
75
82
  raise TranscriptError(f"cannot read transcript: {exc}") from exc
76
83
 
@@ -102,19 +109,18 @@ def _window_label(window: int) -> str:
102
109
  return f"{(window + 500) // 1000}k"
103
110
 
104
111
 
105
- def _format_cost(*, tokens: int, price_per_mtok: float) -> str:
106
- """Cache-read cost, ~0.1x the model's standard input price, truncated
107
- (not rounded) to 2dp - matches `bc`'s `scale=2` semantics from the bash
108
- original. Uses Decimal rather than native float arithmetic: a naive
109
- math.floor(raw * 100) / 100 on a float hits representation error for
110
- ordinary inputs (e.g. tokens=700_000, price=3.00 evaluates to
111
- 0.20999999999999996 in float, one cent short of the correct 0.21) -
112
- caught by adversarial code review on this exact function, not
113
- hypothetical. Decimal(str(price_per_mtok)) avoids reintroducing the same
112
+ def _format_cost(*, tokens: int, cache_read_price_per_mtok: float) -> str:
113
+ """Cost of reading `tokens` from the prompt cache at the model's cache-read
114
+ price, truncated (not rounded) to 2dp - matches `bc`'s `scale=2`
115
+ semantics from the bash original. Uses Decimal rather than native float
116
+ arithmetic: a naive math.floor(raw * 100) / 100 on a float hits
117
+ representation error for ordinary inputs (e.g. tokens=350_000,
118
+ price=0.20 evaluates to 0.06999999999999999 in float, one cent short of
119
+ the correct 0.07). Decimal(str(price)) avoids reintroducing the same
114
120
  float-representation problem by round-tripping the price through its
115
121
  float form first.
116
122
  """
117
- raw = Decimal(tokens) / Decimal(1_000_000) * Decimal(str(price_per_mtok)) * Decimal("0.1")
123
+ raw = Decimal(tokens) / Decimal(1_000_000) * Decimal(str(cache_read_price_per_mtok))
118
124
  return str(raw.quantize(Decimal("0.01"), rounding=ROUND_DOWN))
119
125
 
120
126
 
@@ -134,7 +140,7 @@ def _reason(*, tokens: int, window: int, price: float, name: str, now: str, red:
134
140
  k = _k_tokens(tokens)
135
141
  pct = _pct_of_window(tokens, window)
136
142
  label = _window_label(window)
137
- cost = _format_cost(tokens=tokens, price_per_mtok=price)
143
+ cost = _format_cost(tokens=tokens, cache_read_price_per_mtok=price)
138
144
  emoji = "🔴" if red else "🟠"
139
145
  when = "when you get a natural break" if red else "whenever convenient"
140
146
  return (
@@ -176,7 +182,7 @@ def main(argv: list[str] | None = None) -> int:
176
182
  return 0
177
183
 
178
184
  window = model_info.context_window(model_id)
179
- price = model_info.input_price_per_mtok(model_id)
185
+ price = model_info.cache_read_price_per_mtok(model_id)
180
186
  name = model_info.display_name(model_id)
181
187
  now = datetime.datetime.now().strftime("%H:%M")
182
188
  red = tokens >= THRESHOLD_RED
@@ -0,0 +1,78 @@
1
+ """Model id -> context window size, cache-read price, display name.
2
+
3
+ Consumed by context_window_warning to phrase its nudge in terms of "% of the
4
+ model's actual window" and to estimate a per-turn cache-read cost.
5
+
6
+ Context windows as of 2026-09-29: Fable 5 / Mythos 5 / Opus 5 / Opus 4.6-4.8 /
7
+ Sonnet 5 / Sonnet 5.5 / Opus 5.5 / Fable 5.1 / Mythos 5.1 / Sonnet 4.6 all 1,000,000 tokens
8
+ (the default, not a beta long-context mode); Haiku 4.5 stays at 200,000.
9
+ Prices are each model's published first-party cache-read ("cache hits and
10
+ refreshes") rate per million tokens, from
11
+ https://platform.claude.com/docs/en/about-claude/pricing (checked 2026-09-29).
12
+ They are not a fixed fraction of the input price: Fable 5.1 and Mythos 5.1 read at 0.025x
13
+ and Opus 5.5 at 0.05x, every other model here at 0.1x.
14
+
15
+ Re-check this table whenever a new model ships. A model not matched by any
16
+ case falls through to the default row (200000 tokens / $0.50 per MTok / "an
17
+ unrecognized model") - deliberately the same window as every pre-Claude-5
18
+ model, so an unrecognized model degrades to conservative,
19
+ already-correct-for-most-history behaviour rather than going quiet or firing
20
+ too early.
21
+
22
+ Deliberately not `claude_code_usage.pricing`: that module imports pandas, too
23
+ heavy for a hook that runs on every Stop event. tests/test_pricing.py asserts
24
+ that every cache-read price here matches that module's table.
25
+ """
26
+ from __future__ import annotations
27
+
28
+ import re
29
+
30
+ _WINDOW_1M = {
31
+ "claude-fable-5", "claude-mythos-5",
32
+ "claude-opus-5", "claude-opus-4-8", "claude-opus-4-7", "claude-opus-4-6",
33
+ "claude-sonnet-5", "claude-sonnet-4-6",
34
+ "claude-sonnet-5-5", "claude-opus-5-5", "claude-fable-5-1", "claude-mythos-5-1",
35
+ }
36
+ _CACHE_READ_PRICE = {
37
+ "claude-fable-5-1": 0.25, "claude-mythos-5-1": 0.25, "claude-fable-5": 1.00, "claude-mythos-5": 1.00,
38
+ "claude-opus-5-5": 0.20,
39
+ "claude-opus-5": 0.50, "claude-opus-4-8": 0.50, "claude-opus-4-7": 0.50, "claude-opus-4-6": 0.50,
40
+ "claude-sonnet-5-5": 0.20, "claude-sonnet-5": 0.20, "claude-sonnet-4-6": 0.30,
41
+ "claude-haiku-4-5": 0.10,
42
+ }
43
+ _NAME = {
44
+ "claude-fable-5": "Fable 5", "claude-mythos-5": "Mythos 5",
45
+ "claude-opus-5": "Opus 5", "claude-opus-4-8": "Opus 4.8",
46
+ "claude-opus-4-7": "Opus 4.7", "claude-opus-4-6": "Opus 4.6",
47
+ "claude-sonnet-5": "Sonnet 5", "claude-sonnet-4-6": "Sonnet 4.6",
48
+ "claude-sonnet-5-5": "Sonnet 5.5", "claude-opus-5-5": "Opus 5.5",
49
+ "claude-fable-5-1": "Fable 5.1", "claude-mythos-5-1": "Mythos 5.1",
50
+ "claude-haiku-4-5": "Haiku 4.5",
51
+ }
52
+ _DEFAULT_WINDOW = 200_000
53
+ _DEFAULT_CACHE_READ_PRICE = 0.50
54
+ _DEFAULT_NAME = "an unrecognized model"
55
+
56
+
57
+ _DATED_SNAPSHOT = re.compile(r"(.+)-\d{8}")
58
+
59
+
60
+ def _canonical(model_id: str) -> str:
61
+ """A dated snapshot id (`<id>-YYYYMMDD`) resolves to its undated row. Applied once, and
62
+ only for an exactly-eight-digit suffix: any other suffix (or a snapshot of an unknown id)
63
+ stays unrecognised. `[1m]`/`-latest` are not handled - transcripts' `message.model` never
64
+ carries them."""
65
+ match = _DATED_SNAPSHOT.fullmatch(model_id)
66
+ return match.group(1) if match else model_id
67
+
68
+
69
+ def context_window(model_id: str) -> int:
70
+ return 1_000_000 if _canonical(model_id) in _WINDOW_1M else _DEFAULT_WINDOW
71
+
72
+
73
+ def cache_read_price_per_mtok(model_id: str) -> float:
74
+ return _CACHE_READ_PRICE.get(_canonical(model_id), _DEFAULT_CACHE_READ_PRICE)
75
+
76
+
77
+ def display_name(model_id: str) -> str:
78
+ return _NAME.get(_canonical(model_id), _DEFAULT_NAME)
@@ -56,27 +56,33 @@ def test_corrupt_transcript_raises(tmp_path: Path):
56
56
  cww._current_context_tokens(p)
57
57
 
58
58
 
59
- def test_golden_cost_case_matches_the_pasted_warning():
60
- """tokens=155000, Sonnet 5 ($3.00/MTok) is the exact figure from the
61
- context-warning message pasted at the top of the session that started
62
- this migration: '~155k tokens ... ~$0.04/turn in cache reads'."""
63
- assert cww._format_cost(tokens=155_000, price_per_mtok=3.00) == "0.04"
59
+ def test_cost_is_tokens_times_cache_read_price():
60
+ """155k tokens at a $0.30/MTok cache-read price is $0.0465, shown as 0.04."""
61
+ assert cww._format_cost(tokens=155_000, cache_read_price_per_mtok=0.30) == "0.04"
62
+
63
+
64
+ @pytest.mark.parametrize(
65
+ ("model_id", "tokens", "cost"),
66
+ [("claude-fable-5-1", 400_000, "0.10"), ("claude-sonnet-5-5", 500_000, "0.10")],
67
+ )
68
+ def test_cost_uses_the_models_published_cache_read_price(model_id, tokens, cost):
69
+ price = cww.model_info.cache_read_price_per_mtok(model_id)
70
+ assert cww._format_cost(tokens=tokens, cache_read_price_per_mtok=price) == cost
64
71
 
65
72
 
66
73
  def test_cost_truncates_not_rounds():
67
- """tokens=199_000, price=3.00 -> 0.199*3.00*0.1 = 0.0597 -> bc truncates
74
+ """tokens=199_000, cache-read price 0.30 -> 0.199*0.30 = 0.0597 -> bc truncates
68
75
  to "0.05"; a naive f'{x:.2f}' would round to "0.06". Chosen specifically
69
76
  because truncation and rounding clearly disagree on this input."""
70
- assert cww._format_cost(tokens=199_000, price_per_mtok=3.00) == "0.05"
77
+ assert cww._format_cost(tokens=199_000, cache_read_price_per_mtok=0.30) == "0.05"
71
78
 
72
79
 
73
80
  def test_cost_does_not_lose_a_cent_to_float_representation_error():
74
81
  """math.floor(raw * 100) / 100 on a native float loses a cent here:
75
- 700000/1e6 * 3.00 * 0.1 evaluates to 0.20999999999999996 in float, not
76
- exactly 0.21, so a naive floor gives "0.20". Found by adversarial code
77
- review - not a contrived edge case: 700k tokens is 70% of a Sonnet 5
78
- 1M-token window, an entirely ordinary state for this hook."""
79
- assert cww._format_cost(tokens=700_000, price_per_mtok=3.00) == "0.21"
82
+ 350000/1e6 * 0.20 evaluates to 0.06999999999999999 in float, not
83
+ exactly 0.07, so a naive floor gives "0.06". 350k tokens at the Sonnet 5.x
84
+ / Opus 5.5 cache-read price is an entirely ordinary state for this hook."""
85
+ assert cww._format_cost(tokens=350_000, cache_read_price_per_mtok=0.20) == "0.07"
80
86
 
81
87
 
82
88
  def test_k_and_pct_integer_arithmetic():
@@ -134,7 +140,7 @@ def test_orange_band_emits_block_decision(tmp_path, monkeypatch, capsys):
134
140
  assert payload["decision"] == "block"
135
141
  assert "🟠 CONTEXT" in payload["reason"]
136
142
  assert "~155k tokens" in payload["reason"]
137
- assert "~$0.04/turn" in payload["reason"]
143
+ assert "~$0.03/turn" in payload["reason"] # Sonnet 5 cache reads $0.20/MTok
138
144
 
139
145
 
140
146
  def test_red_band_emits_red_decision(tmp_path, monkeypatch, capsys):
@@ -185,9 +191,10 @@ def test_override_end_to_end_via_real_store(tmp_path, monkeypatch, capsys):
185
191
  @pytest.mark.parametrize(
186
192
  ("model_id", "name", "cost"),
187
193
  [
188
- ("claude-sonnet-5-5", "Sonnet 5.5", "0.07"),
189
- ("claude-opus-5-5", "Opus 5.5", "0.13"),
190
- ("claude-fable-5-1", "Fable 5.1", "0.26"),
194
+ # 266k tokens x published cache-read price ($0.20, $0.20, $0.25 per MTok)
195
+ ("claude-sonnet-5-5", "Sonnet 5.5", "0.05"),
196
+ ("claude-opus-5-5", "Opus 5.5", "0.05"),
197
+ ("claude-fable-5-1", "Fable 5.1", "0.06"),
191
198
  ],
192
199
  )
193
200
  def test_new_5x_models_are_measured_against_their_one_million_token_window(
@@ -203,3 +210,43 @@ def test_new_5x_models_are_measured_against_their_one_million_token_window(
203
210
  assert name in reason
204
211
  assert f"~${cost}/turn" in reason
205
212
  assert "unrecognized" not in reason
213
+
214
+
215
+ def _synthetic_stub() -> dict:
216
+ """The shape Claude Code writes for a non-API assistant entry (e.g. a usage-limit notice)."""
217
+ return {"type": "assistant", "isApiErrorMessage": True, "message": {"model": "<synthetic>",
218
+ "stop_reason": "stop_sequence",
219
+ "usage": {"input_tokens": 0, "output_tokens": 0, "cache_creation_input_tokens": 0,
220
+ "cache_read_input_tokens": 0}}}
221
+
222
+
223
+ def test_trailing_synthetic_entry_does_not_reset_the_count(tmp_path: Path):
224
+ p = tmp_path / "t.jsonl"
225
+ _write_transcript(p, [
226
+ {"type": "assistant", "message": {"model": "claude-sonnet-5-5",
227
+ "usage": {"input_tokens": 500, "cache_creation_input_tokens": 1500, "cache_read_input_tokens": 178000}}},
228
+ _synthetic_stub(),
229
+ ])
230
+ assert cww._current_context_tokens(p) == (180000, "claude-sonnet-5-5")
231
+
232
+
233
+ def test_only_synthetic_entries_behave_like_a_fresh_session(tmp_path: Path):
234
+ p = tmp_path / "t.jsonl"
235
+ _write_transcript(p, [{"type": "user", "message": {"content": "hi"}}, _synthetic_stub()])
236
+ assert cww._current_context_tokens(p) == (0, "")
237
+
238
+
239
+ def test_warning_still_fires_after_a_trailing_synthetic_entry(tmp_path, monkeypatch, capsys):
240
+ p = tmp_path / "t.jsonl"
241
+ _write_transcript(p, [
242
+ {"type": "assistant", "message": {"model": "claude-sonnet-5-5",
243
+ "usage": {"input_tokens": 180000, "cache_creation_input_tokens": 0, "cache_read_input_tokens": 0}}},
244
+ _synthetic_stub(),
245
+ ])
246
+ monkeypatch.setattr(cww, "_is_overridden", lambda session_id: False)
247
+ rc, out = _run_main(monkeypatch, capsys, {"transcript_path": str(p), "session_id": "s1"})
248
+ assert rc == 0
249
+ reason = json.loads(out.out)["reason"]
250
+ assert "~180k tokens" in reason
251
+ assert "Sonnet 5.5" in reason
252
+ assert "unrecognized" not in reason