cc-session-tools 3.10.3__tar.gz → 3.10.4__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 (296) hide show
  1. {cc_session_tools-3.10.3/src/cc_session_tools.egg-info → cc_session_tools-3.10.4}/PKG-INFO +1 -1
  2. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/pyproject.toml +1 -1
  3. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4/src/cc_session_tools.egg-info}/PKG-INFO +1 -1
  4. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/hooks/context_window_warning.py +52 -2
  5. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/hooks/model_info.py +12 -7
  6. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/tests/test_context_window_warning.py +96 -0
  7. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/tests/test_model_info.py +17 -3
  8. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/LICENSE +0 -0
  9. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/README.md +0 -0
  10. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/setup.cfg +0 -0
  11. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/cc_session_tools/__init__.py +0 -0
  12. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/cc_session_tools/cli/__init__.py +0 -0
  13. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/cc_session_tools/cli/ccd.py +0 -0
  14. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/cc_session_tools/cli/ccmsg.py +0 -0
  15. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/cc_session_tools/cli/ccr.py +0 -0
  16. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/cc_session_tools/cli/ccs.py +0 -0
  17. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/cc_session_tools/cli/ccsched.py +0 -0
  18. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/cc_session_tools/cli/ccst.py +0 -0
  19. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/cc_session_tools/cli/migrate_ccmsg.py +0 -0
  20. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/cc_session_tools/cli/migrate_ccsched.py +0 -0
  21. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/cc_session_tools/cli/migrate_sessions_db.py +0 -0
  22. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/cc_session_tools/cli/migrate_telemetry.py +0 -0
  23. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/cc_session_tools/config/hooks-bundle.json +0 -0
  24. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/cc_session_tools/config/session-tag-hook.json +0 -0
  25. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/cc_session_tools/hooks_install.py +0 -0
  26. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/__init__.py +0 -0
  27. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/bun_tools.py +0 -0
  28. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/claude_flags.py +0 -0
  29. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/claude_md_install.py +0 -0
  30. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/context_overrides.py +0 -0
  31. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/db.py +0 -0
  32. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/debug.py +0 -0
  33. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/doctor.py +0 -0
  34. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/doctor_mutes.py +0 -0
  35. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/hook_registry.py +0 -0
  36. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/install_sync.py +0 -0
  37. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/levenshtein.py +0 -0
  38. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/machine_identity.py +0 -0
  39. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/messaging/__init__.py +0 -0
  40. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/messaging/addressing.py +0 -0
  41. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/messaging/cursor.py +0 -0
  42. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/messaging/lock.py +0 -0
  43. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/messaging/message.py +0 -0
  44. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/messaging/move_safety.py +0 -0
  45. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/messaging/repository.py +0 -0
  46. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/messaging/retention.py +0 -0
  47. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/messaging/service.py +0 -0
  48. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/messaging/store.py +0 -0
  49. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/occupancy.py +0 -0
  50. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/paths.py +0 -0
  51. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/pdata/__init__.py +0 -0
  52. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/pdata/backup.py +0 -0
  53. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/pdata/classify.py +0 -0
  54. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/pdata/cutover.py +0 -0
  55. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/pdata/dump.py +0 -0
  56. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/pdata/formatting.py +0 -0
  57. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/pdata/importers.py +0 -0
  58. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/pdata/init_paths.py +0 -0
  59. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/pdata/init_service.py +0 -0
  60. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/pdata/manifest.py +0 -0
  61. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/pdata/naming.py +0 -0
  62. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/pdata/readiness.py +0 -0
  63. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/pdata/rehydrate.py +0 -0
  64. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/pdata/rename_group.py +0 -0
  65. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/pdata/reorganize.py +0 -0
  66. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/pdata/repository.py +0 -0
  67. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/pdata/resolve.py +0 -0
  68. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/pdata/service.py +0 -0
  69. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/pdata/session_output.py +0 -0
  70. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/pdata/store.py +0 -0
  71. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/pdata/sync_check.py +0 -0
  72. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/pdata/sync_lock.py +0 -0
  73. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/pdata/sync_notify.py +0 -0
  74. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/pdata/vector_clock.py +0 -0
  75. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/pdata/vector_clock_store.py +0 -0
  76. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/pdata/verify.py +0 -0
  77. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/pdata/write_log.py +0 -0
  78. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/picker.py +0 -0
  79. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/proc_lock.py +0 -0
  80. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/prompts.py +0 -0
  81. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/roots.py +0 -0
  82. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/rules.py +0 -0
  83. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/scheduler/__init__.py +0 -0
  84. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/scheduler/bundled_jobs.py +0 -0
  85. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/scheduler/cadence.py +0 -0
  86. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/scheduler/cursor.py +0 -0
  87. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/scheduler/digest.py +0 -0
  88. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/scheduler/due.py +0 -0
  89. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/scheduler/duration.py +0 -0
  90. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/scheduler/jobspec.py +0 -0
  91. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/scheduler/ledger.py +0 -0
  92. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/scheduler/lock.py +0 -0
  93. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/scheduler/notify.py +0 -0
  94. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/scheduler/reconcile.py +0 -0
  95. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/scheduler/registry.py +0 -0
  96. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/scheduler/runner.py +0 -0
  97. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/scheduler/state.py +0 -0
  98. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/scheduler/store.py +0 -0
  99. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/scheduler/surface.py +0 -0
  100. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/scheduler/throttle.py +0 -0
  101. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/scheduler/worker.py +0 -0
  102. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/session_gc.py +0 -0
  103. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/sessions.py +0 -0
  104. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/sessions_db.py +0 -0
  105. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/sessions_repair.py +0 -0
  106. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/shell_install.py +0 -0
  107. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/tasklist.py +0 -0
  108. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/telemetry_store.py +0 -0
  109. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/cc_session_tools/lib/text_wrap.py +0 -0
  110. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/cc_session_tools/skills/analyse-cc-usage/SKILL.md +0 -0
  111. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/cc_session_tools/skills/clean-hook-sessions/SKILL.md +0 -0
  112. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/cc_session_tools/skills/clean-hook-sessions/scripts/clean-hook-sessions.py +0 -0
  113. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/cc_session_tools/skills/compact-smart/SKILL.md +0 -0
  114. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/cc_session_tools/skills/context-override/SKILL.md +0 -0
  115. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/cc_session_tools/skills/delete-sessions/SKILL.md +0 -0
  116. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/cc_session_tools/skills/delete-sessions/scripts/delete_sessions.py +0 -0
  117. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/cc_session_tools/skills/do-executor-critic-assessor-loop/SKILL.md +0 -0
  118. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/cc_session_tools/skills/extract-pptx/SKILL.md +0 -0
  119. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/cc_session_tools/skills/extract-pptx/scripts/extract_pptx.py +0 -0
  120. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/cc_session_tools/skills/extract-to-text/SKILL.md +0 -0
  121. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/cc_session_tools/skills/extract-to-text/scripts/extract_to_text.py +0 -0
  122. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/cc_session_tools/skills/find-claude-code-session/SKILL.md +0 -0
  123. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/cc_session_tools/skills/generate-8digit-code/SKILL.md +0 -0
  124. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/cc_session_tools/skills/generate-8digit-code/scripts/generate_8digit_code.py +0 -0
  125. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/cc_session_tools/skills/list-empty-sessions/SKILL.md +0 -0
  126. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/cc_session_tools/skills/list-empty-sessions/scripts/list_empty_sessions.py +0 -0
  127. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/cc_session_tools/skills/manage-recurring-cc-jobs-using-ccsched/SKILL.md +0 -0
  128. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/cc_session_tools/skills/move-session/SKILL.md +0 -0
  129. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/cc_session_tools/skills/move-session/hooks/sessionstart-pending-rename.sh +0 -0
  130. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/cc_session_tools/skills/move-session/scripts/cc_session_rules.py +0 -0
  131. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/cc_session_tools/skills/move-session/scripts/move_session.py +0 -0
  132. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/cc_session_tools/skills/pm-pdata-design-schema/SKILL.md +0 -0
  133. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/cc_session_tools/skills/pm-pdata-do-audit-and-prepare-to-migrate/SKILL.md +0 -0
  134. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/cc_session_tools/skills/pm-pdata-do-init/SKILL.md +0 -0
  135. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/cc_session_tools/skills/pm-pdata-do-manual-migration/SKILL.md +0 -0
  136. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/cc_session_tools/skills/pm-pdata-do-update-consuming-skills/SKILL.md +0 -0
  137. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/cc_session_tools/skills/pm-pdata-do-update-project-docs/SKILL.md +0 -0
  138. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/cc_session_tools/skills/pm-pdata-resolve-conflicts/SKILL.md +0 -0
  139. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/cc_session_tools/skills/pm-project-layout-reference/SKILL.md +0 -0
  140. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/cc_session_tools/skills/pm-update-central-files/SKILL.md +0 -0
  141. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/cc_session_tools/skills/reduce-persistent-context/CALIBRATION.md +0 -0
  142. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/cc_session_tools/skills/reduce-persistent-context/SKILL.md +0 -0
  143. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/cc_session_tools/skills/reduce-persistent-context/scripts/analyze_context.py +0 -0
  144. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/cc_session_tools/skills/reduce-persistent-context/scripts/duplicates.py +0 -0
  145. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/cc_session_tools/skills/reduce-persistent-context/scripts/measure.py +0 -0
  146. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/cc_session_tools/skills/reduce-persistent-context/scripts/report.py +0 -0
  147. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/cc_session_tools/skills/reduce-persistent-context/scripts/tokens.py +0 -0
  148. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/cc_session_tools/skills/reduce-persistent-context/scripts/usage.py +0 -0
  149. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/cc_session_tools/skills/select-agent-model/SKILL.md +0 -0
  150. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/cc_session_tools/skills/send-session-message/SKILL.md +0 -0
  151. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/cc_session_tools/skills/update-command-cache/SKILL.md +0 -0
  152. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/cc_session_tools/skills/update-command-cache/scripts/update_command_cache.py +0 -0
  153. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/cc_session_tools.egg-info/SOURCES.txt +0 -0
  154. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/cc_session_tools.egg-info/dependency_links.txt +0 -0
  155. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/cc_session_tools.egg-info/entry_points.txt +0 -0
  156. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/cc_session_tools.egg-info/requires.txt +0 -0
  157. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/cc_session_tools.egg-info/top_level.txt +0 -0
  158. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/claude_code_usage/__init__.py +0 -0
  159. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/claude_code_usage/attribution.py +0 -0
  160. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/claude_code_usage/cache.py +0 -0
  161. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/claude_code_usage/ccusage_wrapper.py +0 -0
  162. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/claude_code_usage/cli.py +0 -0
  163. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/claude_code_usage/data/pricing.json +0 -0
  164. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/claude_code_usage/parent_inference.py +0 -0
  165. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/claude_code_usage/parser.py +0 -0
  166. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/claude_code_usage/pricing.py +0 -0
  167. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/claude_code_usage/query.py +0 -0
  168. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/claude_code_usage/report.py +0 -0
  169. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/claude_code_usage/schema.py +0 -0
  170. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/claude_code_usage/session_names.py +0 -0
  171. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/hooks/__init__.py +0 -0
  172. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/hooks/after_response.py +0 -0
  173. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/hooks/bash_hard_deny.py +0 -0
  174. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/hooks/bash_security_review.py +0 -0
  175. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/hooks/cache.py +0 -0
  176. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/hooks/catchup.py +0 -0
  177. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/hooks/confirm_8digit.py +0 -0
  178. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/hooks/last_screenshot.py +0 -0
  179. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/hooks/marker_allow.py +0 -0
  180. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/hooks/markers.py +0 -0
  181. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/hooks/messaging_deliver.py +0 -0
  182. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/hooks/normalise.py +0 -0
  183. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/hooks/pdata_sync.py +0 -0
  184. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/hooks/pending_migration.py +0 -0
  185. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/hooks/pending_rename.py +0 -0
  186. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/hooks/script_allowlist.py +0 -0
  187. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/hooks/session_tag.py +0 -0
  188. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/hooks/stats.py +0 -0
  189. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/hooks/telemetry.py +0 -0
  190. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/hooks/telemetry_query.py +0 -0
  191. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/hooks/telemetry_trim.py +0 -0
  192. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/hooks/transcript.py +0 -0
  193. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/src/hooks/worklog_guard.py +0 -0
  194. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/tests/test_after_response.py +0 -0
  195. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/tests/test_attribution.py +0 -0
  196. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/tests/test_bash_hard_deny.py +0 -0
  197. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/tests/test_bash_security_review.py +0 -0
  198. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/tests/test_bash_security_review_allowlist.py +0 -0
  199. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/tests/test_bun_tools.py +0 -0
  200. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/tests/test_cache.py +0 -0
  201. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/tests/test_cache_sqlite.py +0 -0
  202. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/tests/test_ccr_orphans.py +0 -0
  203. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/tests/test_ccs_emptiness.py +0 -0
  204. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/tests/test_ccs_eta.py +0 -0
  205. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/tests/test_ccs_list_mode.py +0 -0
  206. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/tests/test_ccs_scope_flags.py +0 -0
  207. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/tests/test_ccs_sentinel_sort.py +0 -0
  208. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/tests/test_ccs_session_counts.py +0 -0
  209. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/tests/test_ccst_bundle_discovery.py +0 -0
  210. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/tests/test_ccst_ccsched_jobs_cli.py +0 -0
  211. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/tests/test_ccst_cli.py +0 -0
  212. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/tests/test_ccst_context_override_cli.py +0 -0
  213. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/tests/test_ccst_doctor.py +0 -0
  214. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/tests/test_ccst_gc_prune.py +0 -0
  215. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/tests/test_ccst_gc_report.py +0 -0
  216. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/tests/test_ccst_hook_dispatcher.py +0 -0
  217. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/tests/test_ccst_hooks_allowlist.py +0 -0
  218. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/tests/test_ccst_hooks_install_prune.py +0 -0
  219. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/tests/test_ccst_hooks_install_zero_arg.py +0 -0
  220. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/tests/test_ccst_hooks_uninstall.py +0 -0
  221. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/tests/test_ccst_install_everything.py +0 -0
  222. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/tests/test_ccst_machine_identity_cli.py +0 -0
  223. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/tests/test_ccst_main_gate.py +0 -0
  224. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/tests/test_ccst_pdata_cli.py +0 -0
  225. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/tests/test_ccst_pdata_init_cli.py +0 -0
  226. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/tests/test_ccst_pdata_readiness_cli.py +0 -0
  227. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/tests/test_ccst_pdata_reconcile_cli.py +0 -0
  228. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/tests/test_ccst_pdata_rename_group_cli.py +0 -0
  229. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/tests/test_ccst_pdata_reorganize_cli.py +0 -0
  230. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/tests/test_ccst_pdata_sync_cli.py +0 -0
  231. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/tests/test_ccst_pdata_verify_cli.py +0 -0
  232. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/tests/test_ccst_repair_sessions_cli.py +0 -0
  233. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/tests/test_ccst_sessions_cli.py +0 -0
  234. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/tests/test_ccst_shell_install.py +0 -0
  235. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/tests/test_ccst_skills_install.py +0 -0
  236. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/tests/test_ccst_skills_uninstall.py +0 -0
  237. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/tests/test_ccst_telemetry_query.py +0 -0
  238. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/tests/test_ccst_telemetry_trim.py +0 -0
  239. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/tests/test_ccusage_wrapper.py +0 -0
  240. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/tests/test_claude_flags.py +0 -0
  241. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/tests/test_claude_md_install.py +0 -0
  242. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/tests/test_cli.py +0 -0
  243. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/tests/test_cli_ccd.py +0 -0
  244. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/tests/test_cli_ccd_dry_run.py +0 -0
  245. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/tests/test_cli_ccr.py +0 -0
  246. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/tests/test_cli_ccs.py +0 -0
  247. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/tests/test_cli_version.py +0 -0
  248. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/tests/test_confirm_8digit.py +0 -0
  249. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/tests/test_context_overrides.py +0 -0
  250. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/tests/test_db.py +0 -0
  251. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/tests/test_debug.py +0 -0
  252. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/tests/test_doctor_mutes.py +0 -0
  253. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/tests/test_empty_session.py +0 -0
  254. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/tests/test_hook_cache.py +0 -0
  255. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/tests/test_hooks_install.py +0 -0
  256. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/tests/test_hooks_install_records.py +0 -0
  257. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/tests/test_install_sync.py +0 -0
  258. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/tests/test_last_screenshot.py +0 -0
  259. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/tests/test_levenshtein.py +0 -0
  260. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/tests/test_machine_identity.py +0 -0
  261. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/tests/test_marker_allow.py +0 -0
  262. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/tests/test_migrate_ccmsg.py +0 -0
  263. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/tests/test_migrate_ccsched.py +0 -0
  264. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/tests/test_migrate_sessions_db.py +0 -0
  265. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/tests/test_migrate_telemetry.py +0 -0
  266. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/tests/test_normalise.py +0 -0
  267. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/tests/test_occupancy.py +0 -0
  268. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/tests/test_parent_inference.py +0 -0
  269. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/tests/test_parser.py +0 -0
  270. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/tests/test_paths.py +0 -0
  271. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/tests/test_pdata_audit_skill.py +0 -0
  272. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/tests/test_pdata_post_migration_skills.py +0 -0
  273. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/tests/test_pending_migration_hook.py +0 -0
  274. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/tests/test_picker.py +0 -0
  275. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/tests/test_pricing.py +0 -0
  276. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/tests/test_proc_lock.py +0 -0
  277. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/tests/test_prompts.py +0 -0
  278. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/tests/test_query.py +0 -0
  279. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/tests/test_report.py +0 -0
  280. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/tests/test_roots.py +0 -0
  281. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/tests/test_rules.py +0 -0
  282. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/tests/test_scheduler_bundled_jobs.py +0 -0
  283. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/tests/test_schema.py +0 -0
  284. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/tests/test_script_allowlist.py +0 -0
  285. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/tests/test_session_names.py +0 -0
  286. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/tests/test_session_tag.py +0 -0
  287. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/tests/test_sessions.py +0 -0
  288. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/tests/test_sessions_db.py +0 -0
  289. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/tests/test_sessions_db_migration_chain.py +0 -0
  290. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/tests/test_sessions_repair.py +0 -0
  291. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/tests/test_tasklist.py +0 -0
  292. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/tests/test_telemetry.py +0 -0
  293. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/tests/test_telemetry_store.py +0 -0
  294. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/tests/test_text_wrap.py +0 -0
  295. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/tests/test_transcript.py +0 -0
  296. {cc_session_tools-3.10.3 → cc_session_tools-3.10.4}/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.3
3
+ Version: 3.10.4
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.3"
7
+ version = "3.10.4"
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" }
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cc-session-tools
3
- Version: 3.10.3
3
+ Version: 3.10.4
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
@@ -26,6 +26,7 @@ from __future__ import annotations
26
26
 
27
27
  import datetime
28
28
  import json
29
+ import re
29
30
  import sys
30
31
  from decimal import ROUND_DOWN, Decimal
31
32
  from pathlib import Path
@@ -155,6 +156,48 @@ def _reason(*, tokens: int, window: int, price: float, name: str, now: str, red:
155
156
  )
156
157
 
157
158
 
159
+ REMEDIATION_HINT = (
160
+ "To fix: add the id to src/hooks/model_info.py in claude-code-session-tools; if ccst is just out "
161
+ "of date, run `uv tool upgrade cc-session-tools` (installed from PyPI with uv) or "
162
+ "`uv tool install --reinstall <path to your checkout>` (local checkout)."
163
+ )
164
+
165
+ _ID_DISALLOWED = re.compile(r"[^A-Za-z0-9._:<>\[\]-]")
166
+
167
+
168
+ def _model_phrase(model_id: str) -> str:
169
+ """How the unknown model is named in the message. Characters outside the set real ids use are
170
+ replaced, so a corrupt or hostile transcript value cannot break the quoted lines the assistant
171
+ is told to echo."""
172
+ if not model_id:
173
+ return "an unknown model (no model id was recorded)"
174
+ return f"model `{_ID_DISALLOWED.sub('?', model_id)}`"
175
+
176
+
177
+ def _reason_unknown(*, tokens: int, window: int, price: float, model_id: str, now: str, red: bool) -> str:
178
+ """Message for a model id missing from model_info's table: the window and price are
179
+ assumptions and the text says so, instead of presenting them as facts."""
180
+ k = _k_tokens(tokens)
181
+ pct = _pct_of_window(tokens, window)
182
+ label = _window_label(window)
183
+ cost = _format_cost(tokens=tokens, cache_read_price_per_mtok=price)
184
+ model = _model_phrase(model_id)
185
+ emoji = "🔴" if red else "🟠"
186
+ when = "when you get a natural break" if red else "whenever convenient"
187
+ return (
188
+ f"The context window has passed {k}k tokens. The session's {model} is not in ccst's model "
189
+ f"table, so the window size is ASSUMED to be {label} tokens; the real window may be much "
190
+ f"larger (1M for current models) and any percentage may be wrong. THIS IS A WARNING ONLY - "
191
+ f"output the two lines below at the start of your response, then end your turn as you "
192
+ f"normally would. Do not restart or repeat any work.\n"
193
+ f"'{emoji} CONTEXT ({now}): ~{k}k tokens used; window size ASSUMED ({label}) for {model} - "
194
+ f"the real window may be much larger, so ~{pct}% is unreliable. ~${cost}/turn assumes the "
195
+ f"default ${price:.2f}/MTok cache-read price. This is a nudge, not a limit - keep going; "
196
+ f"/compact {when}. {REMEDIATION_HINT}'\n"
197
+ f"'(To silence this warning for the rest of the session, run /context-override.)'"
198
+ )
199
+
200
+
158
201
  def main(argv: list[str] | None = None) -> int:
159
202
  try:
160
203
  stdin_obj = json.loads(sys.stdin.read() or "{}")
@@ -183,11 +226,18 @@ def main(argv: list[str] | None = None) -> int:
183
226
 
184
227
  window = model_info.context_window(model_id)
185
228
  price = model_info.cache_read_price_per_mtok(model_id)
186
- name = model_info.display_name(model_id)
187
229
  now = datetime.datetime.now().strftime("%H:%M")
188
230
  red = tokens >= THRESHOLD_RED
189
231
 
190
- reason = _reason(tokens=tokens, window=window, price=price, name=name, now=now, red=red)
232
+ if model_info.is_known(model_id):
233
+ reason = _reason(
234
+ tokens=tokens, window=window, price=price, name=model_info.display_name(model_id),
235
+ now=now, red=red,
236
+ )
237
+ else:
238
+ reason = _reason_unknown(
239
+ tokens=tokens, window=window, price=price, model_id=model_id, now=now, red=red,
240
+ )
191
241
  print(json.dumps({"decision": "block", "reason": reason}))
192
242
  return 0
193
243
 
@@ -13,11 +13,12 @@ They are not a fixed fraction of the input price: Fable 5.1 and Mythos 5.1 read
13
13
  and Opus 5.5 at 0.05x, every other model here at 0.1x.
14
14
 
15
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,
16
+ case (`is_known` is False) falls through to the default window and price
17
+ (200000 tokens / $0.50 per MTok) - deliberately the same window as every
18
+ pre-Claude-5 model, so an unknown model degrades to conservative,
19
19
  already-correct-for-most-history behaviour rather than going quiet or firing
20
- too early.
20
+ too early. Those defaults are assumptions, and the warning says so; only
21
+ `display_name` has no default (it raises KeyError for an unknown id).
21
22
 
22
23
  Deliberately not `claude_code_usage.pricing`: that module imports pandas, too
23
24
  heavy for a hook that runs on every Stop event. tests/test_pricing.py asserts
@@ -51,7 +52,6 @@ _NAME = {
51
52
  }
52
53
  _DEFAULT_WINDOW = 200_000
53
54
  _DEFAULT_CACHE_READ_PRICE = 0.50
54
- _DEFAULT_NAME = "an unrecognized model"
55
55
 
56
56
 
57
57
  _DATED_SNAPSHOT = re.compile(r"(.+)-\d{8}")
@@ -60,7 +60,7 @@ _DATED_SNAPSHOT = re.compile(r"(.+)-\d{8}")
60
60
  def _canonical(model_id: str) -> str:
61
61
  """A dated snapshot id (`<id>-YYYYMMDD`) resolves to its undated row. Applied once, and
62
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
63
+ stays unknown. `[1m]`/`-latest` are not handled - transcripts' `message.model` never
64
64
  carries them."""
65
65
  match = _DATED_SNAPSHOT.fullmatch(model_id)
66
66
  return match.group(1) if match else model_id
@@ -74,5 +74,10 @@ def cache_read_price_per_mtok(model_id: str) -> float:
74
74
  return _CACHE_READ_PRICE.get(_canonical(model_id), _DEFAULT_CACHE_READ_PRICE)
75
75
 
76
76
 
77
+ def is_known(model_id: str) -> bool:
78
+ return _canonical(model_id) in _NAME
79
+
80
+
77
81
  def display_name(model_id: str) -> str:
78
- return _NAME.get(_canonical(model_id), _DEFAULT_NAME)
82
+ """Raises KeyError for an unknown id: callers check `is_known` first."""
83
+ return _NAME[_canonical(model_id)]
@@ -250,3 +250,99 @@ def test_warning_still_fires_after_a_trailing_synthetic_entry(tmp_path, monkeypa
250
250
  assert "~180k tokens" in reason
251
251
  assert "Sonnet 5.5" in reason
252
252
  assert "unrecognized" not in reason
253
+
254
+
255
+ def _fire(tmp_path, monkeypatch, capsys, model, tokens=162000):
256
+ entry = {"usage": {"input_tokens": tokens, "cache_creation_input_tokens": 0, "cache_read_input_tokens": 0}}
257
+ if model is not None:
258
+ entry["model"] = model
259
+ p = tmp_path / "t.jsonl"
260
+ _write_transcript(p, [{"type": "assistant", "message": entry}])
261
+ monkeypatch.setattr(cww, "_is_overridden", lambda session_id: False)
262
+ rc, out = _run_main(monkeypatch, capsys, {"transcript_path": str(p), "session_id": "s1"})
263
+ assert rc == 0
264
+ return json.loads(out.out)["reason"]
265
+
266
+
267
+ def _assert_assumed_wording(reason: str) -> None:
268
+ instruction, visible = reason.split("\n")[0], reason.split("\n")[1]
269
+ for text in (instruction, visible):
270
+ assert "ASSUMED" in text
271
+ assert "may be much larger" in text
272
+ assert "200k" in text
273
+ assert "unreliable" in text or "may be wrong" in text
274
+ assert "unrecognized model" not in text
275
+ assert "unrecognised model" not in text
276
+ assert "unreliable" in visible
277
+ assert "assumes the default $0.50/MTok cache-read price" in visible
278
+ assert "~$0.08/turn" in visible
279
+ assert "src/hooks/model_info.py" in visible
280
+ assert "uv tool upgrade cc-session-tools" in visible
281
+ assert "uv tool install --reinstall" in visible
282
+
283
+
284
+ @pytest.mark.parametrize("model_id", ["claude-sonnet-9-9", "claude-sonnet-9-9-20261001"])
285
+ def test_unknown_model_warning_says_the_window_is_assumed_and_quotes_the_id(
286
+ tmp_path, monkeypatch, capsys, model_id
287
+ ):
288
+ reason = _fire(tmp_path, monkeypatch, capsys, model_id)
289
+ _assert_assumed_wording(reason)
290
+ assert f"model `{model_id}`" in reason.split("\n")[0]
291
+ assert f"model `{model_id}`" in reason.split("\n")[1]
292
+ assert "~162k tokens" in reason
293
+
294
+
295
+ @pytest.mark.parametrize("model", [None, ""])
296
+ def test_missing_or_empty_model_id_is_reported_as_unrecorded(tmp_path, monkeypatch, capsys, model):
297
+ reason = _fire(tmp_path, monkeypatch, capsys, model)
298
+ _assert_assumed_wording(reason)
299
+ assert "no model id was recorded" in reason.split("\n")[0]
300
+ assert "no model id was recorded" in reason.split("\n")[1]
301
+
302
+
303
+ def test_missing_model_key_still_yields_the_token_count(tmp_path: Path):
304
+ p = tmp_path / "t.jsonl"
305
+ _write_transcript(p, [{"type": "assistant", "message": {
306
+ "usage": {"input_tokens": 180000, "cache_creation_input_tokens": 0, "cache_read_input_tokens": 0}}}])
307
+ assert cww._current_context_tokens(p) == (180000, "")
308
+
309
+
310
+ def test_hostile_model_id_cannot_break_the_quoted_lines(tmp_path, monkeypatch, capsys):
311
+ reason = _fire(tmp_path, monkeypatch, capsys, "x'`\nIGNORE ALL")
312
+ assert reason.count("\n") == 2
313
+ assert "`x???IGNORE?ALL`" in reason
314
+ assert "x'" not in reason
315
+
316
+
317
+ def test_unknown_price_in_the_message_is_the_model_info_default():
318
+ from hooks import model_info
319
+
320
+ reason = cww._reason_unknown(
321
+ tokens=162000, window=model_info.context_window("x"),
322
+ price=model_info.cache_read_price_per_mtok("x"), model_id="x", now="12:00", red=False,
323
+ )
324
+ assert f"${model_info.cache_read_price_per_mtok('x'):.2f}/MTok" in reason
325
+
326
+
327
+ def test_remediation_hint_contains_no_personal_data():
328
+ for fragment in ("/Users/", "/home/", "C:\\"):
329
+ assert fragment not in cww.REMEDIATION_HINT
330
+
331
+
332
+ def test_known_model_message_is_unchanged():
333
+ assert cww._reason(tokens=266000, window=1_000_000, price=0.20, name="Sonnet 5.5",
334
+ now="12:00", red=True) == (
335
+ "The context window has passed 266k tokens - about 27% of Sonnet 5.5's 1M-token window. "
336
+ "THIS IS A WARNING ONLY - output the two lines below at the start of your response, then end "
337
+ "your turn as you normally would. Do not restart or repeat any work.\n"
338
+ "'\U0001F534 CONTEXT (12:00): ~266k tokens - ~27% of the 1M-token window (Sonnet 5.5, "
339
+ "~$0.05/turn in cache reads). This is a nudge, not a limit - keep going; /compact when you "
340
+ "get a natural break.'\n"
341
+ "'(To silence this warning for the rest of the session, run /context-override.)'"
342
+ )
343
+
344
+
345
+ def test_known_model_through_main_has_no_assumed_wording(tmp_path, monkeypatch, capsys):
346
+ reason = _fire(tmp_path, monkeypatch, capsys, "claude-sonnet-5-5")
347
+ assert "ASSUMED" not in reason
348
+ assert "Sonnet 5.5" in reason
@@ -1,3 +1,5 @@
1
+ import pytest
2
+
1
3
  from hooks import model_info
2
4
 
3
5
  # (model id, context window, published cache-read price per MTok, display name)
@@ -28,11 +30,23 @@ def test_known_models():
28
30
  def test_unrecognized_model_falls_back():
29
31
  assert model_info.context_window("claude-nonexistent-9") == 200_000
30
32
  assert model_info.cache_read_price_per_mtok("claude-nonexistent-9") == 0.50
31
- assert model_info.display_name("claude-nonexistent-9") == "an unrecognized model"
33
+ assert model_info.is_known("claude-nonexistent-9") is False
32
34
 
33
35
 
34
36
  def test_empty_model_id_falls_back():
35
37
  assert model_info.context_window("") == 200_000
38
+ assert model_info.is_known("") is False
39
+
40
+
41
+ def test_known_and_dated_known_ids_are_known():
42
+ for model_id, *_ in CASES:
43
+ assert model_info.is_known(model_id) is True, model_id
44
+ assert model_info.is_known("claude-sonnet-5-5-20261001") is True
45
+
46
+
47
+ def test_display_name_of_an_unknown_id_raises_rather_than_inventing_a_name():
48
+ with pytest.raises(KeyError):
49
+ model_info.display_name("claude-nonexistent-9")
36
50
 
37
51
 
38
52
  def test_dated_snapshot_ids_resolve_like_their_family_id():
@@ -59,11 +73,11 @@ def test_unknown_dated_and_decorated_ids_stay_unrecognised():
59
73
  "claude-haiku-4-5-garbage",
60
74
  ):
61
75
  assert model_info.context_window(model_id) == 200_000, model_id
62
- assert model_info.display_name(model_id) == "an unrecognized model", model_id
76
+ assert model_info.is_known(model_id) is False, model_id
63
77
 
64
78
 
65
79
  def test_id_that_merely_starts_with_a_known_id_is_not_recognised():
66
80
  """Guards against a future lazy prefix implementation (already true before the fix):
67
81
  `claude-sonnet-5-9` must not inherit `claude-sonnet-5`'s row."""
68
82
  assert model_info.context_window("claude-sonnet-5-9") == 200_000
69
- assert model_info.display_name("claude-sonnet-5-9") == "an unrecognized model"
83
+ assert model_info.is_known("claude-sonnet-5-9") is False