dota2-hero-sounds 1.0.0

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 (446) hide show
  1. package/README.md +107 -0
  2. package/dist/claude-hooks.d.ts +17 -0
  3. package/dist/claude-hooks.js +106 -0
  4. package/dist/cli.d.ts +4 -0
  5. package/dist/cli.js +229 -0
  6. package/dist/codex-hooks.d.ts +23 -0
  7. package/dist/codex-hooks.js +329 -0
  8. package/dist/config.d.ts +6 -0
  9. package/dist/config.js +31 -0
  10. package/dist/heroes.d.ts +21 -0
  11. package/dist/heroes.js +50 -0
  12. package/dist/install-files.d.ts +26 -0
  13. package/dist/install-files.js +83 -0
  14. package/dist/opencode-plugin.d.ts +20 -0
  15. package/dist/opencode-plugin.js +158 -0
  16. package/dist/pi-extension.d.ts +22 -0
  17. package/dist/pi-extension.js +61 -0
  18. package/dist/play-sound.d.ts +29 -0
  19. package/dist/play-sound.js +106 -0
  20. package/dist/play.d.ts +6 -0
  21. package/dist/play.js +8 -0
  22. package/package.json +54 -0
  23. package/pi-extension/index.ts +117 -0
  24. package/pi-extension/package.json +17 -0
  25. package/sounds/attention/Vo_alchemist_alch_ability_acid_06.mp3 +0 -0
  26. package/sounds/attention/Vo_alchemist_alch_ability_concoc_03.mp3 +0 -0
  27. package/sounds/attention/Vo_alchemist_alch_ability_concoc_06.mp3 +0 -0
  28. package/sounds/attention/Vo_alchemist_alch_attack_05.mp3 +0 -0
  29. package/sounds/attention/Vo_alchemist_alch_attack_15.mp3 +0 -0
  30. package/sounds/attention/Vo_alchemist_alch_cast_02.mp3 +0 -0
  31. package/sounds/attention/Vo_alchemist_alch_move_20.mp3 +0 -0
  32. package/sounds/attention/Vo_alchemist_alch_move_21.mp3 +0 -0
  33. package/sounds/attention/Vo_antimage_anti_ability_manavoid_08.mp3 +0 -0
  34. package/sounds/attention/Vo_antimage_anti_cast_01.mp3 +0 -0
  35. package/sounds/attention/Vo_antimage_anti_magicuser_01.mp3 +0 -0
  36. package/sounds/attention/Vo_antimage_anti_magicuser_06.mp3 +0 -0
  37. package/sounds/attention/Vo_antimage_anti_resist_02.mp3 +0 -0
  38. package/sounds/attention/Vo_axe_axe_ability_berserk_02.mp3 +0 -0
  39. package/sounds/attention/Vo_axe_axe_ally_08.mp3 +0 -0
  40. package/sounds/attention/Vo_axe_axe_blink_02.mp3 +0 -0
  41. package/sounds/attention/Vo_axe_axe_blinkcull_01.mp3 +0 -0
  42. package/sounds/attention/Vo_axe_axe_lasthit_06.mp3 +0 -0
  43. package/sounds/attention/Vo_axe_axe_level_01.mp3 +0 -0
  44. package/sounds/attention/Vo_axe_axe_level_04.mp3 +0 -0
  45. package/sounds/attention/Vo_axe_axe_move_02.mp3 +0 -0
  46. package/sounds/attention/Vo_axe_axe_move_10.mp3 +0 -0
  47. package/sounds/attention/Vo_axe_axe_move_11.mp3 +0 -0
  48. package/sounds/attention/Vo_bloodseeker_blod_ability_rupture_04.mp3 +0 -0
  49. package/sounds/attention/Vo_bloodseeker_blod_attack_04.mp3 +0 -0
  50. package/sounds/attention/Vo_bloodseeker_blod_level_01.mp3 +0 -0
  51. package/sounds/attention/Vo_bounty_hunter_bount_ability_shur_02.mp3 +0 -0
  52. package/sounds/attention/Vo_bounty_hunter_bount_ability_track_02.mp3 +0 -0
  53. package/sounds/attention/Vo_bounty_hunter_bount_ability_track_04.mp3 +0 -0
  54. package/sounds/attention/Vo_bounty_hunter_bount_ability_windwalk_04.mp3 +0 -0
  55. package/sounds/attention/Vo_bounty_hunter_bount_level_01.mp3 +0 -0
  56. package/sounds/attention/Vo_bounty_hunter_bount_level_02.mp3 +0 -0
  57. package/sounds/attention/Vo_bounty_hunter_bount_level_09.mp3 +0 -0
  58. package/sounds/attention/Vo_brewmaster_brew_ability_drunkenhaze_02.mp3 +0 -0
  59. package/sounds/attention/Vo_brewmaster_brew_ability_drunkenhaze_04.mp3 +0 -0
  60. package/sounds/attention/Vo_brewmaster_brew_ability_drunkenhaze_06.mp3 +0 -0
  61. package/sounds/attention/Vo_brewmaster_brew_level_02.mp3 +0 -0
  62. package/sounds/attention/Vo_brewmaster_brew_move_15.mp3 +0 -0
  63. package/sounds/attention/Vo_bristleback_bristle_attack_01.mp3 +0 -0
  64. package/sounds/attention/Vo_bristleback_bristle_attack_11.mp3 +0 -0
  65. package/sounds/attention/Vo_bristleback_bristle_attack_21.mp3 +0 -0
  66. package/sounds/attention/Vo_bristleback_bristle_attack_22.mp3 +0 -0
  67. package/sounds/attention/Vo_bristleback_bristle_levelup_01.mp3 +0 -0
  68. package/sounds/attention/Vo_bristleback_bristle_nasal_goo_01.mp3 +0 -0
  69. package/sounds/attention/Vo_bristleback_bristle_nasal_goo_02.mp3 +0 -0
  70. package/sounds/attention/Vo_bristleback_bristle_nasal_goo_03.mp3 +0 -0
  71. package/sounds/attention/Vo_bristleback_bristle_purch_05.mp3 +0 -0
  72. package/sounds/attention/Vo_bristleback_bristle_quill_spray_01.mp3 +0 -0
  73. package/sounds/attention/Vo_bristleback_bristle_quill_spray_05.mp3 +0 -0
  74. package/sounds/attention/Vo_crystalmaiden_cm_levelup_02.mp3 +0 -0
  75. package/sounds/attention/Vo_crystalmaiden_cm_lina_07.mp3 +0 -0
  76. package/sounds/attention/Vo_crystalmaiden_cm_lina_09.mp3 +0 -0
  77. package/sounds/attention/Vo_crystalmaiden_cm_lina_11.mp3 +0 -0
  78. package/sounds/attention/Vo_dark_seer_dkseer_move_10.mp3 +0 -0
  79. package/sounds/attention/Vo_drowranger_dro_cast_01.mp3 +0 -0
  80. package/sounds/attention/Vo_drowranger_dro_cast_02.mp3 +0 -0
  81. package/sounds/attention/Vo_drowranger_dro_lasthit_02.mp3 +0 -0
  82. package/sounds/attention/Vo_drowranger_drow_ally_01.mp3 +0 -0
  83. package/sounds/attention/Vo_kunkka_kunk_ability_ghostshp_02.mp3 +0 -0
  84. package/sounds/attention/Vo_kunkka_kunk_ability_tidebrng_01.mp3 +0 -0
  85. package/sounds/attention/Vo_kunkka_kunk_ability_tidebrng_02.mp3 +0 -0
  86. package/sounds/attention/Vo_kunkka_kunk_ability_torrent_03.mp3 +0 -0
  87. package/sounds/attention/Vo_kunkka_kunk_ability_xmark_01.mp3 +0 -0
  88. package/sounds/attention/Vo_kunkka_kunk_cast_02-1.mp3 +0 -0
  89. package/sounds/attention/Vo_kunkka_kunk_cast_02.mp3 +0 -0
  90. package/sounds/attention/Vo_kunkka_kunk_move_02.mp3 +0 -0
  91. package/sounds/attention/Vo_kunkka_kunk_move_05.mp3 +0 -0
  92. package/sounds/attention/Vo_kunkka_kunk_move_11.mp3 +0 -0
  93. package/sounds/attention/Vo_lina_lina_ally_03.mp3 +0 -0
  94. package/sounds/attention/Vo_lina_lina_ally_05.mp3 +0 -0
  95. package/sounds/attention/Vo_lina_lina_cm_02.mp3 +0 -0
  96. package/sounds/attention/Vo_lina_lina_cm_06.mp3 +0 -0
  97. package/sounds/attention/Vo_lina_lina_cm_10.mp3 +0 -0
  98. package/sounds/attention/Vo_lina_lina_level_05.mp3 +0 -0
  99. package/sounds/attention/Vo_ogre_magi_ogmag_ability_multi_01.mp3 +0 -0
  100. package/sounds/attention/Vo_ogre_magi_ogmag_ability_multi_02.mp3 +0 -0
  101. package/sounds/attention/Vo_ogre_magi_ogmag_ability_multi_08.mp3 +0 -0
  102. package/sounds/attention/Vo_ogre_magi_ogmag_ability_multi_09.mp3 +0 -0
  103. package/sounds/attention/Vo_ogre_magi_ogmag_attack_03.mp3 +0 -0
  104. package/sounds/attention/Vo_ogre_magi_ogmag_attack_04.mp3 +0 -0
  105. package/sounds/attention/Vo_ogre_magi_ogmag_attack_05.mp3 +0 -0
  106. package/sounds/attention/Vo_ogre_magi_ogmag_cast_01.mp3 +0 -0
  107. package/sounds/attention/Vo_ogre_magi_ogmag_cast_03.mp3 +0 -0
  108. package/sounds/attention/Vo_ogre_magi_ogmag_lasthit_01.mp3 +0 -0
  109. package/sounds/attention/Vo_ogre_magi_ogmag_lasthit_09.mp3 +0 -0
  110. package/sounds/attention/Vo_ogre_magi_ogmag_laugh_14.mp3 +0 -0
  111. package/sounds/attention/Vo_ogre_magi_ogmag_level_01.mp3 +0 -0
  112. package/sounds/attention/Vo_ogre_magi_ogmag_level_02.mp3 +0 -0
  113. package/sounds/attention/Vo_ogre_magi_ogmag_level_03.mp3 +0 -0
  114. package/sounds/attention/Vo_ogre_magi_ogmag_level_05.mp3 +0 -0
  115. package/sounds/attention/Vo_ogre_magi_ogmag_level_06.mp3 +0 -0
  116. package/sounds/attention/Vo_ogre_magi_ogmag_level_07.mp3 +0 -0
  117. package/sounds/attention/Vo_ogre_magi_ogmag_move_04.mp3 +0 -0
  118. package/sounds/attention/Vo_ogre_magi_ogmag_move_11.mp3 +0 -0
  119. package/sounds/attention/Vo_ogre_magi_ogmag_move_14.mp3 +0 -0
  120. package/sounds/attention/Vo_ogre_magi_ogmag_move_19.mp3 +0 -0
  121. package/sounds/attention/Vo_ogre_magi_ogmag_move_20.mp3 +0 -0
  122. package/sounds/attention/Vo_ogre_magi_ogmag_move_21.mp3 +0 -0
  123. package/sounds/attention/Vo_omniknight_omni_ability_degaura_03.mp3 +0 -0
  124. package/sounds/attention/Vo_omniknight_omni_ability_degaura_06.mp3 +0 -0
  125. package/sounds/attention/Vo_omniknight_omni_ability_degaura_09.mp3 +0 -0
  126. package/sounds/attention/Vo_omniknight_omni_ability_guard_06.mp3 +0 -0
  127. package/sounds/attention/Vo_omniknight_omni_ability_guard_10.mp3 +0 -0
  128. package/sounds/attention/Vo_omniknight_omni_ability_repel_02.mp3 +0 -0
  129. package/sounds/attention/Vo_omniknight_omni_attack_09.mp3 +0 -0
  130. package/sounds/attention/Vo_omniknight_omni_cast_02.mp3 +0 -0
  131. package/sounds/attention/Vo_omniknight_omni_lasthit_01.mp3 +0 -0
  132. package/sounds/attention/Vo_omniknight_omni_level_04.mp3 +0 -0
  133. package/sounds/attention/Vo_omniknight_omni_level_08.mp3 +0 -0
  134. package/sounds/attention/Vo_omniknight_omni_move_03.mp3 +0 -0
  135. package/sounds/attention/Vo_omniknight_omni_move_11.mp3 +0 -0
  136. package/sounds/attention/Vo_pudge_pud_ability_devour_15.mp3 +0 -0
  137. package/sounds/attention/Vo_pudge_pud_ability_hook_03.mp3 +0 -0
  138. package/sounds/attention/Vo_pudge_pud_ability_hook_04.mp3 +0 -0
  139. package/sounds/attention/Vo_pudge_pud_ability_hook_07.mp3 +0 -0
  140. package/sounds/attention/Vo_pudge_pud_ability_hook_09.mp3 +0 -0
  141. package/sounds/attention/Vo_pudge_pud_ability_hook_10-1.mp3 +0 -0
  142. package/sounds/attention/Vo_pudge_pud_ability_hook_10.mp3 +0 -0
  143. package/sounds/attention/Vo_pudge_pud_ability_hook_miss_06.mp3 +0 -0
  144. package/sounds/attention/Vo_pudge_pud_ability_rot_07.mp3 +0 -0
  145. package/sounds/attention/Vo_pudge_pud_ability_rot_12.mp3 +0 -0
  146. package/sounds/attention/Vo_pudge_pud_acknow_05.mp3 +0 -0
  147. package/sounds/attention/Vo_pudge_pud_attack_01.mp3 +0 -0
  148. package/sounds/attention/Vo_pudge_pud_attack_03.mp3 +0 -0
  149. package/sounds/attention/Vo_pudge_pud_attack_09.mp3 +0 -0
  150. package/sounds/attention/Vo_pudge_pud_attack_11.mp3 +0 -0
  151. package/sounds/attention/Vo_pudge_pud_cast_04.mp3 +0 -0
  152. package/sounds/attention/Vo_pudge_pud_move_01.mp3 +0 -0
  153. package/sounds/attention/Vo_queenofpain_pain_ability_screamofpain_01.mp3 +0 -0
  154. package/sounds/attention/Vo_queenofpain_pain_ability_screamofpain_02.mp3 +0 -0
  155. package/sounds/attention/Vo_queenofpain_pain_ability_screamofpain_04.mp3 +0 -0
  156. package/sounds/attention/Vo_queenofpain_pain_ability_shadowstrike_02.mp3 +0 -0
  157. package/sounds/attention/Vo_queenofpain_pain_bottle_02.mp3 +0 -0
  158. package/sounds/attention/Vo_queenofpain_pain_cast_03.mp3 +0 -0
  159. package/sounds/attention/Vo_queenofpain_pain_first_02.mp3 +0 -0
  160. package/sounds/attention/Vo_queenofpain_pain_lasthit_01.mp3 +0 -0
  161. package/sounds/attention/Vo_queenofpain_pain_lasthit_05.mp3 +0 -0
  162. package/sounds/attention/Vo_queenofpain_pain_levelup_02.mp3 +0 -0
  163. package/sounds/attention/Vo_queenofpain_pain_levelup_05.mp3 +0 -0
  164. package/sounds/attention/Vo_queenofpain_pain_purch_02.mp3 +0 -0
  165. package/sounds/attention/Vo_queenofpain_pain_taunt_02.mp3 +0 -0
  166. package/sounds/attention/Vo_rattletrap_ratt_attack_03.mp3 +0 -0
  167. package/sounds/attention/Vo_rattletrap_ratt_attack_10.mp3 +0 -0
  168. package/sounds/attention/Vo_rattletrap_ratt_move_24.mp3 +0 -0
  169. package/sounds/attention/Vo_silencer_silen_ability_curse_05.mp3 +0 -0
  170. package/sounds/attention/Vo_silencer_silen_ability_intsteal_02.mp3 +0 -0
  171. package/sounds/attention/Vo_silencer_silen_ability_intsteal_03.mp3 +0 -0
  172. package/sounds/attention/Vo_silencer_silen_ability_intsteal_04.mp3 +0 -0
  173. package/sounds/attention/Vo_silencer_silen_ability_intsteal_07.mp3 +0 -0
  174. package/sounds/attention/Vo_silencer_silen_attack_14.mp3 +0 -0
  175. package/sounds/attention/Vo_silencer_silen_bottle_02.mp3 +0 -0
  176. package/sounds/attention/Vo_silencer_silen_bottle_05.mp3 +0 -0
  177. package/sounds/attention/Vo_silencer_silen_cast_02.mp3 +0 -0
  178. package/sounds/attention/Vo_silencer_silen_first_01.mp3 +0 -0
  179. package/sounds/attention/Vo_silencer_silen_lasthit_06.mp3 +0 -0
  180. package/sounds/attention/Vo_silencer_silen_move_04.mp3 +0 -0
  181. package/sounds/attention/Vo_stormspirit_ss_ability_lightning_01.mp3 +0 -0
  182. package/sounds/attention/Vo_stormspirit_ss_ability_lightning_04.mp3 +0 -0
  183. package/sounds/attention/Vo_stormspirit_ss_ability_static_04.mp3 +0 -0
  184. package/sounds/attention/Vo_stormspirit_ss_ability_static_06.mp3 +0 -0
  185. package/sounds/attention/Vo_stormspirit_ss_attack_03.mp3 +0 -0
  186. package/sounds/attention/Vo_stormspirit_ss_bottle_03.mp3 +0 -0
  187. package/sounds/attention/Vo_stormspirit_ss_level_02.mp3 +0 -0
  188. package/sounds/attention/Vo_stormspirit_ss_move_13.mp3 +0 -0
  189. package/sounds/attention/Vo_stormspirit_stormspirit_ally_01.mp3 +0 -0
  190. package/sounds/attention/Vo_stormspirit_stormspirit_ally_03.mp3 +0 -0
  191. package/sounds/attention/Vo_stormspirit_stormspirit_fastres_01.mp3 +0 -0
  192. package/sounds/attention/Vo_tidehunter_tide_ability_gush_02.mp3 +0 -0
  193. package/sounds/attention/Vo_tidehunter_tide_arcane_01.mp3 +0 -0
  194. package/sounds/attention/Vo_tidehunter_tide_attack_01.mp3 +0 -0
  195. package/sounds/attention/Vo_tidehunter_tide_attack_07.mp3 +0 -0
  196. package/sounds/attention/Vo_tidehunter_tide_bottle_02.mp3 +0 -0
  197. package/sounds/attention/Vo_tidehunter_tide_level_03.mp3 +0 -0
  198. package/sounds/attention/Vo_tidehunter_tide_move_01.mp3 +0 -0
  199. package/sounds/attention/Vo_tidehunter_tide_move_05.mp3 +0 -0
  200. package/sounds/attention/Vo_windrunner_wind_ability_focusfire_04.mp3 +0 -0
  201. package/sounds/attention/Vo_windrunner_wind_attack_04.mp3 +0 -0
  202. package/sounds/attention/Vo_windrunner_wind_attack_06.mp3 +0 -0
  203. package/sounds/attention/Vo_zuus_zeus_ally_205.mp3 +0 -0
  204. package/sounds/attention/Vo_zuus_zeus_mars_ally_07.mp3 +0 -0
  205. package/sounds/attention/Vo_zuus_zeus_mars_ally_12.mp3 +0 -0
  206. package/sounds/attention/Vo_zuus_zeus_mars_ally_14.mp3 +0 -0
  207. package/sounds/attention/Vo_zuus_zuus_ability_thunder_02.mp3 +0 -0
  208. package/sounds/attention/Vo_zuus_zuus_lasthit_03.mp3 +0 -0
  209. package/sounds/attention/Vo_zuus_zuus_level_01.mp3 +0 -0
  210. package/sounds/attention/Vo_zuus_zuus_level_03.mp3 +0 -0
  211. package/sounds/attention/Vo_zuus_zuus_purch_01.mp3 +0 -0
  212. package/sounds/error/Vo_antimage_anti_respawn_01.mp3 +0 -0
  213. package/sounds/error/Vo_antimage_anti_respawn_04.mp3 +0 -0
  214. package/sounds/error/Vo_axe_axe_respawn_01.mp3 +0 -0
  215. package/sounds/error/Vo_axe_axe_respawn_04.mp3 +0 -0
  216. package/sounds/error/Vo_axe_axe_respawn_08.mp3 +0 -0
  217. package/sounds/error/Vo_bounty_hunter_bount_respawn_02.mp3 +0 -0
  218. package/sounds/error/Vo_bounty_hunter_bount_respawn_04.mp3 +0 -0
  219. package/sounds/error/Vo_bounty_hunter_bount_respawn_05.mp3 +0 -0
  220. package/sounds/error/Vo_lina_lina_respawn_03.mp3 +0 -0
  221. package/sounds/error/Vo_lina_lina_respawn_08.mp3 +0 -0
  222. package/sounds/error/Vo_lina_lina_respawn_11.mp3 +0 -0
  223. package/sounds/error/Vo_ogre_magi_ogmag_respawn_06.mp3 +0 -0
  224. package/sounds/error/Vo_omniknight_omni_death_03.mp3 +0 -0
  225. package/sounds/error/Vo_omniknight_omni_death_06.mp3 +0 -0
  226. package/sounds/error/Vo_omniknight_omni_nomana_01.mp3 +0 -0
  227. package/sounds/error/Vo_omniknight_omni_respawn_02.mp3 +0 -0
  228. package/sounds/error/Vo_omniknight_omni_respawn_06.mp3 +0 -0
  229. package/sounds/error/Vo_omniknight_omni_respawn_08.mp3 +0 -0
  230. package/sounds/error/Vo_omniknight_omni_respawn_09.mp3 +0 -0
  231. package/sounds/error/Vo_queenofpain_pain_respawn_01.mp3 +0 -0
  232. package/sounds/error/Vo_queenofpain_pain_respawn_02.mp3 +0 -0
  233. package/sounds/error/Vo_queenofpain_pain_respawn_04.mp3 +0 -0
  234. package/sounds/error/Vo_queenofpain_pain_respawn_09.mp3 +0 -0
  235. package/sounds/error/Vo_silencer_silen_respawn_01.mp3 +0 -0
  236. package/sounds/error/Vo_silencer_silen_respawn_04.mp3 +0 -0
  237. package/sounds/error/Vo_silencer_silen_respawn_10.mp3 +0 -0
  238. package/sounds/error/Vo_stormspirit_ss_respawn_01.mp3 +0 -0
  239. package/sounds/error/Vo_stormspirit_ss_respawn_05.mp3 +0 -0
  240. package/sounds/error/Vo_tidehunter_tide_death_03.mp3 +0 -0
  241. package/sounds/error/Vo_tidehunter_tide_death_09.mp3 +0 -0
  242. package/sounds/error/Vo_tidehunter_tide_respawn_03.mp3 +0 -0
  243. package/sounds/error/Vo_windrunner_wind_respawn_02.mp3 +0 -0
  244. package/sounds/error/Vo_windrunner_wind_respawn_03.mp3 +0 -0
  245. package/sounds/error/Vo_windrunner_wind_respawn_05.mp3 +0 -0
  246. package/sounds/error/Vo_windrunner_wind_respawn_09.mp3 +0 -0
  247. package/sounds/error/Vo_zuus_zeus_mars_death_04.mp3 +0 -0
  248. package/sounds/error/Vo_zuus_zeus_mars_death_06_02.mp3 +0 -0
  249. package/sounds/error/Vo_zuus_zeus_mars_death_07_02.mp3 +0 -0
  250. package/sounds/error/Vo_zuus_zeus_mars_death_13_05.mp3 +0 -0
  251. package/sounds/error/Vo_zuus_zuus_death_08.mp3 +0 -0
  252. package/sounds/error/Vo_zuus_zuus_death_09.mp3 +0 -0
  253. package/sounds/error/Vo_zuus_zuus_respawn_01.mp3 +0 -0
  254. package/sounds/error/Vo_zuus_zuus_respawn_03.mp3 +0 -0
  255. package/sounds/error/Vo_zuus_zuus_respawn_06.mp3 +0 -0
  256. package/sounds/error/Vo_zuus_zuus_respawn_09.mp3 +0 -0
  257. package/sounds/error/Vo_zuus_zuus_respawn_10.mp3 +0 -0
  258. package/sounds/start/Vo_alchemist_alch_spawn_04.mp3 +0 -0
  259. package/sounds/start/Vo_alchemist_alch_spawn_05.mp3 +0 -0
  260. package/sounds/start/Vo_alchemist_alch_spawn_06.mp3 +0 -0
  261. package/sounds/start/Vo_antimage_anti_spawn_04.mp3 +0 -0
  262. package/sounds/start/Vo_axe_axe_battlebegins_01.mp3 +0 -0
  263. package/sounds/start/Vo_axe_axe_spawn_02.mp3 +0 -0
  264. package/sounds/start/Vo_axe_axe_spawn_04.mp3 +0 -0
  265. package/sounds/start/Vo_axe_axe_spawn_08.mp3 +0 -0
  266. package/sounds/start/Vo_axe_axe_spawn_10.mp3 +0 -0
  267. package/sounds/start/Vo_bloodseeker_blod_spawn_03.mp3 +0 -0
  268. package/sounds/start/Vo_bloodseeker_blod_spawn_05.mp3 +0 -0
  269. package/sounds/start/Vo_bloodseeker_blod_spawn_08.mp3 +0 -0
  270. package/sounds/start/Vo_bounty_hunter_bount_battlebegins_01.mp3 +0 -0
  271. package/sounds/start/Vo_brewmaster_brew_spawn_06.mp3 +0 -0
  272. package/sounds/start/Vo_bristleback_bristle_begin_01.mp3 +0 -0
  273. package/sounds/start/Vo_bristleback_bristle_begin_02.mp3 +0 -0
  274. package/sounds/start/Vo_bristleback_bristle_begin_03.mp3 +0 -0
  275. package/sounds/start/Vo_bristleback_bristle_spawn_03.mp3 +0 -0
  276. package/sounds/start/Vo_crystalmaiden_cm_battlebegins_01.mp3 +0 -0
  277. package/sounds/start/Vo_crystalmaiden_cm_spawn_02.mp3 +0 -0
  278. package/sounds/start/Vo_dark_seer_dkseer_spawn_03.mp3 +0 -0
  279. package/sounds/start/Vo_drowranger_dro_spawn_04.mp3 +0 -0
  280. package/sounds/start/Vo_drowranger_dro_spawn_05.mp3 +0 -0
  281. package/sounds/start/Vo_drowranger_drow_battlebegins_01.mp3 +0 -0
  282. package/sounds/start/Vo_kunkka_kunk_battlebegins_01.mp3 +0 -0
  283. package/sounds/start/Vo_kunkka_kunk_spawn_06.mp3 +0 -0
  284. package/sounds/start/Vo_kunkka_kunk_spawn_10.mp3 +0 -0
  285. package/sounds/start/Vo_lina_lina_battlebegins_01.mp3 +0 -0
  286. package/sounds/start/Vo_lina_lina_spawn_05.mp3 +0 -0
  287. package/sounds/start/Vo_ogre_magi_ogmag_battlebegins_01.mp3 +0 -0
  288. package/sounds/start/Vo_ogre_magi_ogmag_spawn_06.mp3 +0 -0
  289. package/sounds/start/Vo_omniknight_omni_spawn_02.mp3 +0 -0
  290. package/sounds/start/Vo_omniknight_omni_spawn_04.mp3 +0 -0
  291. package/sounds/start/Vo_omniknight_omni_spawn_05.mp3 +0 -0
  292. package/sounds/start/Vo_pudge_pud_spawn_04.mp3 +0 -0
  293. package/sounds/start/Vo_queenofpain_pain_spawn_02.mp3 +0 -0
  294. package/sounds/start/Vo_rattletrap_ratt_spawn_03.mp3 +0 -0
  295. package/sounds/start/Vo_silencer_silen_spawn_02.mp3 +0 -0
  296. package/sounds/start/Vo_silencer_silen_spawn_03.mp3 +0 -0
  297. package/sounds/start/Vo_stormspirit_ss_spawn_04.mp3 +0 -0
  298. package/sounds/start/Vo_stormspirit_ss_spawn_06.mp3 +0 -0
  299. package/sounds/start/Vo_tidehunter_tide_spawn_04.mp3 +0 -0
  300. package/sounds/start/Vo_windrunner_wind_spawn_06.mp3 +0 -0
  301. package/sounds/start/Vo_zuus_zuus_battlebegins_01.mp3 +0 -0
  302. package/sounds/start/Vo_zuus_zuus_battlebegins_02.mp3 +0 -0
  303. package/sounds/start/Vo_zuus_zuus_spawn_04.mp3 +0 -0
  304. package/sounds/start/Vo_zuus_zuus_spawn_05.mp3 +0 -0
  305. package/sounds/start/Vo_zuus_zuus_spawn_06.mp3 +0 -0
  306. package/sounds/start/Vo_zuus_zuus_spawn_07.mp3 +0 -0
  307. package/sounds/start/Vo_zuus_zuus_spawn_08.mp3 +0 -0
  308. package/sounds/success/Vo_alchemist_alch_kill_15.mp3 +0 -0
  309. package/sounds/success/Vo_alchemist_alch_rival_20.mp3 +0 -0
  310. package/sounds/success/Vo_antimage_anti_deny_07.mp3 +0 -0
  311. package/sounds/success/Vo_antimage_anti_kill_02.mp3 +0 -0
  312. package/sounds/success/Vo_axe_axe_deny_02.mp3 +0 -0
  313. package/sounds/success/Vo_axe_axe_deny_08.mp3 +0 -0
  314. package/sounds/success/Vo_axe_axe_deny_15.mp3 +0 -0
  315. package/sounds/success/Vo_axe_axe_immort_02.mp3 +0 -0
  316. package/sounds/success/Vo_axe_axe_inthebag_02.mp3 +0 -0
  317. package/sounds/success/Vo_axe_axe_kill_01.mp3 +0 -0
  318. package/sounds/success/Vo_axe_axe_kill_06.mp3 +0 -0
  319. package/sounds/success/Vo_axe_axe_kill_08.mp3 +0 -0
  320. package/sounds/success/Vo_axe_axe_kill_12.mp3 +0 -0
  321. package/sounds/success/Vo_axe_axe_kill_14.mp3 +0 -0
  322. package/sounds/success/Vo_axe_axe_rival_01.mp3 +0 -0
  323. package/sounds/success/Vo_axe_axe_rival_02.mp3 +0 -0
  324. package/sounds/success/Vo_axe_axe_rival_08.mp3 +0 -0
  325. package/sounds/success/Vo_axe_axe_rival_09.mp3 +0 -0
  326. package/sounds/success/Vo_axe_axe_rival_10.mp3 +0 -0
  327. package/sounds/success/Vo_axe_axe_rival_14.mp3 +0 -0
  328. package/sounds/success/Vo_axe_axe_rival_16.mp3 +0 -0
  329. package/sounds/success/Vo_axe_axe_rival_17.mp3 +0 -0
  330. package/sounds/success/Vo_axe_axe_rival_19.mp3 +0 -0
  331. package/sounds/success/Vo_axe_axe_rival_20.mp3 +0 -0
  332. package/sounds/success/Vo_axe_axe_rival_21.mp3 +0 -0
  333. package/sounds/success/Vo_axe_axe_rival_22.mp3 +0 -0
  334. package/sounds/success/Vo_bloodseeker_blod_inthebag_01.mp3 +0 -0
  335. package/sounds/success/Vo_bounty_hunter_bount_deny_01.mp3 +0 -0
  336. package/sounds/success/Vo_bounty_hunter_bount_deny_03.mp3 +0 -0
  337. package/sounds/success/Vo_bounty_hunter_bount_kill_14.mp3 +0 -0
  338. package/sounds/success/Vo_brewmaster_brew_kill_02.mp3 +0 -0
  339. package/sounds/success/Vo_brewmaster_brew_kill_04.mp3 +0 -0
  340. package/sounds/success/Vo_bristleback_bristle_deny_10.mp3 +0 -0
  341. package/sounds/success/Vo_bristleback_bristle_deny_11.mp3 +0 -0
  342. package/sounds/success/Vo_bristleback_bristle_firstblood_02.mp3 +0 -0
  343. package/sounds/success/Vo_bristleback_bristle_inthebag_01.mp3 +0 -0
  344. package/sounds/success/Vo_bristleback_bristle_kill_02.mp3 +0 -0
  345. package/sounds/success/Vo_bristleback_bristle_kill_06.mp3 +0 -0
  346. package/sounds/success/Vo_bristleback_bristle_kill_11.mp3 +0 -0
  347. package/sounds/success/Vo_bristleback_bristle_rival_06.mp3 +0 -0
  348. package/sounds/success/Vo_bristleback_bristle_rival_46.mp3 +0 -0
  349. package/sounds/success/Vo_crystalmaiden_cm_kill_03.mp3 +0 -0
  350. package/sounds/success/Vo_crystalmaiden_cm_kill_09.mp3 +0 -0
  351. package/sounds/success/Vo_crystalmaiden_cm_kill_10.mp3 +0 -0
  352. package/sounds/success/Vo_crystalmaiden_cm_rival_02.mp3 +0 -0
  353. package/sounds/success/Vo_crystalmaiden_cm_rival_04.mp3 +0 -0
  354. package/sounds/success/Vo_crystalmaiden_cm_rival_05.mp3 +0 -0
  355. package/sounds/success/Vo_crystalmaiden_cm_rival_08.mp3 +0 -0
  356. package/sounds/success/Vo_crystalmaiden_cm_rival_10.mp3 +0 -0
  357. package/sounds/success/Vo_crystalmaiden_cm_rival_15.mp3 +0 -0
  358. package/sounds/success/Vo_drowranger_dro_deny_04.mp3 +0 -0
  359. package/sounds/success/Vo_drowranger_drow_kill_10.mp3 +0 -0
  360. package/sounds/success/Vo_kunkka_kunk_inthebag_01.mp3 +0 -0
  361. package/sounds/success/Vo_kunkka_kunk_kill_10.mp3 +0 -0
  362. package/sounds/success/Vo_kunkka_kunk_kill_13.mp3 +0 -0
  363. package/sounds/success/Vo_kunkka_kunk_killspecial_01.mp3 +0 -0
  364. package/sounds/success/Vo_kunkka_kunk_rival_10.mp3 +0 -0
  365. package/sounds/success/Vo_kunkka_kunk_rival_21.mp3 +0 -0
  366. package/sounds/success/Vo_kunkka_kunk_rival_29.mp3 +0 -0
  367. package/sounds/success/Vo_kunkka_kunk_rival_34.mp3 +0 -0
  368. package/sounds/success/Vo_lina_lina_deny_12.mp3 +0 -0
  369. package/sounds/success/Vo_lina_lina_kill_02.mp3 +0 -0
  370. package/sounds/success/Vo_lina_lina_kill_07.mp3 +0 -0
  371. package/sounds/success/Vo_lina_lina_kill_08.mp3 +0 -0
  372. package/sounds/success/Vo_lina_lina_rival_03.mp3 +0 -0
  373. package/sounds/success/Vo_lina_lina_rival_06.mp3 +0 -0
  374. package/sounds/success/Vo_lina_lina_rival_10.mp3 +0 -0
  375. package/sounds/success/Vo_lina_lina_rival_12.mp3 +0 -0
  376. package/sounds/success/Vo_lina_lina_rival_13.mp3 +0 -0
  377. package/sounds/success/Vo_lina_lina_rival_14.mp3 +0 -0
  378. package/sounds/success/Vo_lina_lina_rival_15.mp3 +0 -0
  379. package/sounds/success/Vo_ogre_magi_ogmag_firstblood_02.mp3 +0 -0
  380. package/sounds/success/Vo_ogre_magi_ogmag_kill_03.mp3 +0 -0
  381. package/sounds/success/Vo_ogre_magi_ogmag_kill_06.mp3 +0 -0
  382. package/sounds/success/Vo_ogre_magi_ogmag_kill_12.mp3 +0 -0
  383. package/sounds/success/Vo_ogre_magi_ogmag_rival_01.mp3 +0 -0
  384. package/sounds/success/Vo_ogre_magi_ogmag_rival_02.mp3 +0 -0
  385. package/sounds/success/Vo_ogre_magi_ogmag_rival_03.mp3 +0 -0
  386. package/sounds/success/Vo_ogre_magi_ogmag_rival_04.mp3 +0 -0
  387. package/sounds/success/Vo_ogre_magi_ogmag_rival_05.mp3 +0 -0
  388. package/sounds/success/Vo_ogre_magi_ogmag_rival_07.mp3 +0 -0
  389. package/sounds/success/Vo_ogre_magi_ogmag_rival_10.mp3 +0 -0
  390. package/sounds/success/Vo_ogre_magi_ogmag_rival_20.mp3 +0 -0
  391. package/sounds/success/Vo_omniknight_omni_deny_07.mp3 +0 -0
  392. package/sounds/success/Vo_omniknight_omni_immort_02.mp3 +0 -0
  393. package/sounds/success/Vo_omniknight_omni_kill_02.mp3 +0 -0
  394. package/sounds/success/Vo_omniknight_omni_kill_03.mp3 +0 -0
  395. package/sounds/success/Vo_omniknight_omni_kill_08.mp3 +0 -0
  396. package/sounds/success/Vo_pudge_pud_deny_01.mp3 +0 -0
  397. package/sounds/success/Vo_pudge_pud_deny_09.mp3 +0 -0
  398. package/sounds/success/Vo_pudge_pud_immort_02.mp3 +0 -0
  399. package/sounds/success/Vo_pudge_pud_rival_06.mp3 +0 -0
  400. package/sounds/success/Vo_queenofpain_pain_deny_01.mp3 +0 -0
  401. package/sounds/success/Vo_queenofpain_pain_kill_01.mp3 +0 -0
  402. package/sounds/success/Vo_queenofpain_pain_kill_02.mp3 +0 -0
  403. package/sounds/success/Vo_queenofpain_pain_kill_04.mp3 +0 -0
  404. package/sounds/success/Vo_queenofpain_pain_kill_05.mp3 +0 -0
  405. package/sounds/success/Vo_queenofpain_pain_kill_08.mp3 +0 -0
  406. package/sounds/success/Vo_queenofpain_pain_kill_11.mp3 +0 -0
  407. package/sounds/success/Vo_queenofpain_pain_rival_10.mp3 +0 -0
  408. package/sounds/success/Vo_silencer_silen_kill_10.mp3 +0 -0
  409. package/sounds/success/Vo_silencer_silen_kill_13.mp3 +0 -0
  410. package/sounds/success/Vo_silencer_silen_kill_14.mp3 +0 -0
  411. package/sounds/success/Vo_silencer_silen_rival_01.mp3 +0 -0
  412. package/sounds/success/Vo_silencer_silen_rival_02.mp3 +0 -0
  413. package/sounds/success/Vo_silencer_silen_rival_05.mp3 +0 -0
  414. package/sounds/success/Vo_silencer_silen_rival_11.mp3 +0 -0
  415. package/sounds/success/Vo_stormspirit_ss_deny_01.mp3 +0 -0
  416. package/sounds/success/Vo_stormspirit_ss_deny_04.mp3 +0 -0
  417. package/sounds/success/Vo_stormspirit_ss_kill_03.mp3 +0 -0
  418. package/sounds/success/Vo_stormspirit_stormspirit_rival_02.mp3 +0 -0
  419. package/sounds/success/Vo_stormspirit_stormspirit_rival_03.mp3 +0 -0
  420. package/sounds/success/Vo_stormspirit_stormspirit_rival_18.mp3 +0 -0
  421. package/sounds/success/Vo_tidehunter_tide_deny_01.mp3 +0 -0
  422. package/sounds/success/Vo_tidehunter_tide_kill_04.mp3 +0 -0
  423. package/sounds/success/Vo_tidehunter_tide_rival_04.mp3 +0 -0
  424. package/sounds/success/Vo_tidehunter_tide_rival_05.mp3 +0 -0
  425. package/sounds/success/Vo_tidehunter_tide_rival_19.mp3 +0 -0
  426. package/sounds/success/Vo_windrunner_wind_deny_01.mp3 +0 -0
  427. package/sounds/success/Vo_windrunner_wind_deny_04.mp3 +0 -0
  428. package/sounds/success/Vo_windrunner_wind_deny_07.mp3 +0 -0
  429. package/sounds/success/Vo_windrunner_wind_kill_06.mp3 +0 -0
  430. package/sounds/success/Vo_windrunner_wind_kill_09.mp3 +0 -0
  431. package/sounds/success/Vo_windrunner_wind_kill_11.mp3 +0 -0
  432. package/sounds/success/Vo_windrunner_wind_killspecial_01.mp3 +0 -0
  433. package/sounds/success/Vo_zuus_zeus_mars_kill_02.mp3 +0 -0
  434. package/sounds/success/Vo_zuus_zeus_mars_kill_06.mp3 +0 -0
  435. package/sounds/success/Vo_zuus_zeus_mars_kill_08.mp3 +0 -0
  436. package/sounds/success/Vo_zuus_zeus_mars_kill_12.mp3 +0 -0
  437. package/sounds/success/Vo_zuus_zeus_mars_kill_13.mp3 +0 -0
  438. package/sounds/success/Vo_zuus_zeus_rival_205.mp3 +0 -0
  439. package/sounds/success/Vo_zuus_zuus_deny_03.mp3 +0 -0
  440. package/sounds/success/Vo_zuus_zuus_kill_01.mp3 +0 -0
  441. package/sounds/success/Vo_zuus_zuus_kill_02.mp3 +0 -0
  442. package/sounds/success/Vo_zuus_zuus_kill_03.mp3 +0 -0
  443. package/sounds/success/Vo_zuus_zuus_kill_06.mp3 +0 -0
  444. package/sounds/success/Vo_zuus_zuus_kill_10.mp3 +0 -0
  445. package/sounds/success/Vo_zuus_zuus_rival_13.mp3 +0 -0
  446. package/sounds/success/Vo_zuus_zuus_rival_14.mp3 +0 -0
package/README.md ADDED
@@ -0,0 +1,107 @@
1
+ # dota2-hero-sounds
2
+
3
+ Dota 2 hero voice line notifications for [Claude Code](https://docs.anthropic.com/en/docs/claude-code), [OpenCode](https://opencode.ai), and [Pi](https://pi.dev). Get notified with voice lines from Axe, Crystal Maiden, Pudge, Zeus, and many more when your AI coding assistant completes tasks, hits errors, or needs your attention.
4
+
5
+ ## Quick Start
6
+
7
+ ```bash
8
+ npx dota2-hero-sounds install
9
+ ```
10
+
11
+ This auto-detects which tools you have installed and configures them. Use flags to target a specific tool:
12
+
13
+ ```bash
14
+ npx dota2-hero-sounds install --claude # Claude Code only
15
+ npx dota2-hero-sounds install --opencode # OpenCode only
16
+ npx dota2-hero-sounds install --pi # Pi only
17
+ npx dota2-hero-sounds install --all # All three
18
+ ```
19
+
20
+ ## How It Works
21
+
22
+ When events occur in your coding tool, a random hero speaks:
23
+
24
+ | Event | Category | Example Lines |
25
+ |-------|----------|---------------|
26
+ | Task complete | `success` | "Yes, Axe kills you!", "Burns, doesn't it?", "Told you a storm was coming!" |
27
+ | Error | `error` | "An anchor around my neck!", "Okay, sure, I've made some mistakes.", "That was just a warm-up." |
28
+ | Needs attention | `attention` | "Come to Pudge!", "Prepare thyself.", "Agony awaits." |
29
+ | Session start | `start` | "Let the carnage begin!", "Storm Spirit is alive!", "Your God has arrived." |
30
+
31
+ A random sound is picked from the matching category each time. Sounds have a 3-second cooldown to prevent overlapping voice lines.
32
+
33
+ ## Hero Selection
34
+
35
+ By default, sounds are picked randomly from all heroes. You can set preferred heroes:
36
+
37
+ ```bash
38
+ npx dota2-hero-sounds hero list # Show available heroes with sound counts
39
+ npx dota2-hero-sounds hero set axe pudge # Only play Axe and Pudge sounds
40
+ npx dota2-hero-sounds hero show # Show current preference
41
+ npx dota2-hero-sounds hero clear # Reset to all heroes
42
+ ```
43
+
44
+ Hero preferences are saved to `~/.config/dota2-sounds/config.json` and take effect immediately — no reinstall needed. If a selected hero has no sounds for a category, it falls back to all heroes for that category.
45
+
46
+ ## CLI Commands
47
+
48
+ ```bash
49
+ dota2-hero-sounds install # Install hooks/plugins
50
+ dota2-hero-sounds uninstall # Remove everything cleanly
51
+ dota2-hero-sounds test # Play one sound per category
52
+ dota2-hero-sounds list # Show all sounds by category
53
+ dota2-hero-sounds hero list # Show heroes with per-category counts
54
+ dota2-hero-sounds hero set # Set preferred heroes
55
+ dota2-hero-sounds help # Show help
56
+ ```
57
+
58
+ ## What Gets Installed
59
+
60
+ **Claude Code** — Hooks added to `~/.claude/settings.json`:
61
+ - `Stop` → plays success sound
62
+ - `PostToolUseFailure` → plays error sound
63
+ - `Notification` → plays attention sound
64
+ - `SessionStart` → plays start sound
65
+
66
+ **OpenCode** — Plugin written to `~/.config/opencode/plugins/dota2-sounds.js`:
67
+ - `session.status` busy→idle transition → plays success sound
68
+ - `session.error` → plays error sound
69
+ - `permission.asked` → plays attention sound
70
+ - Plugin init → plays start sound (session.created fires too early)
71
+
72
+ **Pi** — Extension installed via `pi install` as a Pi package:
73
+ - `session_start` → plays start sound
74
+ - `agent_end` → plays success sound
75
+ - `tool_execution_end` (when `isError`) → plays error sound
76
+ - `session_shutdown` → plays error sound
77
+ - *Attention sound not available* — Pi has no permission/notification event
78
+
79
+ ## Uninstall
80
+
81
+ ```bash
82
+ npx dota2-hero-sounds uninstall
83
+ ```
84
+
85
+ This cleanly removes only the hooks/plugins added by this package — your other settings are untouched.
86
+
87
+ ## Adding Custom Sounds
88
+
89
+ 1. Add `.mp3` files to the appropriate `sounds/<category>/` subdirectory
90
+ 2. Sound files are discovered at runtime — no code changes needed
91
+ 3. Re-run `dota2-hero-sounds install` to update the OpenCode plugin with new sounds
92
+
93
+ Sound files should follow the naming convention `Vo_<hero>_<shortname>_<type>_<num>.mp3` to enable future hero-based filtering.
94
+
95
+ ## Finding More Sounds
96
+
97
+ Browse the full collection of Dota 2 hero voice lines at the [Dota 2 Wiki Audio Category](https://dota2.fandom.com/wiki/Category:Audio). Each hero has hundreds of voice lines covering spawns, kills, abilities, and more.
98
+
99
+ ## Requirements
100
+
101
+ - **macOS** (uses `afplay` for audio playback)
102
+ - **Node.js** 18+
103
+ - Claude Code, OpenCode, and/or Pi installed
104
+
105
+ ## License
106
+
107
+ MIT
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Get the path to Claude Code's global settings file.
3
+ */
4
+ export declare function getClaudeSettingsPath(): string;
5
+ /**
6
+ * Check if Claude Code config directory exists.
7
+ */
8
+ export declare function isClaudeCodeAvailable(): boolean;
9
+ /**
10
+ * Install Claude Code hooks into ~/.claude/settings.json.
11
+ * Merges with existing hooks without overwriting user-defined ones.
12
+ */
13
+ export declare function installClaudeHooks(playScriptPath: string): void;
14
+ /**
15
+ * Remove all dota2-hero-sounds hooks from ~/.claude/settings.json.
16
+ */
17
+ export declare function uninstallClaudeHooks(): void;
@@ -0,0 +1,106 @@
1
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
2
+ import { homedir } from 'node:os';
3
+ import { join } from 'node:path';
4
+ /**
5
+ * Marker used to identify hooks added by this package,
6
+ * so we can cleanly uninstall without touching user-defined hooks.
7
+ */
8
+ const HOOK_MARKER = 'dota2-hero-sounds';
9
+ /**
10
+ * Get the path to Claude Code's global settings file.
11
+ */
12
+ export function getClaudeSettingsPath() {
13
+ return join(homedir(), '.claude', 'settings.json');
14
+ }
15
+ /**
16
+ * Check if Claude Code config directory exists.
17
+ */
18
+ export function isClaudeCodeAvailable() {
19
+ return existsSync(join(homedir(), '.claude'));
20
+ }
21
+ /**
22
+ * Build the hooks configuration for Claude Code.
23
+ * @param playScriptPath - Absolute path to dist/play.js
24
+ */
25
+ function buildHooks(playScriptPath) {
26
+ const makeHook = (category) => ({
27
+ matcher: '',
28
+ hooks: [
29
+ {
30
+ type: 'command',
31
+ command: `node "${playScriptPath}" ${category} # ${HOOK_MARKER}`,
32
+ },
33
+ ],
34
+ });
35
+ return {
36
+ Stop: [makeHook('success')],
37
+ PostToolUseFailure: [makeHook('error')],
38
+ Notification: [makeHook('attention')],
39
+ SessionStart: [makeHook('start')],
40
+ };
41
+ }
42
+ /**
43
+ * Install Claude Code hooks into ~/.claude/settings.json.
44
+ * Merges with existing hooks without overwriting user-defined ones.
45
+ */
46
+ export function installClaudeHooks(playScriptPath) {
47
+ const settingsPath = getClaudeSettingsPath();
48
+ const settingsDir = join(homedir(), '.claude');
49
+ // Ensure directory exists
50
+ if (!existsSync(settingsDir)) {
51
+ mkdirSync(settingsDir, { recursive: true });
52
+ }
53
+ // Read existing settings or start fresh
54
+ let settings = {};
55
+ if (existsSync(settingsPath)) {
56
+ const raw = readFileSync(settingsPath, 'utf-8');
57
+ settings = JSON.parse(raw);
58
+ }
59
+ // Remove any existing dota2-hero-sounds hooks first (clean reinstall)
60
+ if (settings.hooks) {
61
+ for (const event of Object.keys(settings.hooks)) {
62
+ settings.hooks[event] = settings.hooks[event].filter((entry) => !entry.hooks.some((h) => h.command.includes(HOOK_MARKER)));
63
+ // Remove the event key entirely if no hooks remain
64
+ if (settings.hooks[event].length === 0) {
65
+ delete settings.hooks[event];
66
+ }
67
+ }
68
+ }
69
+ // Merge new hooks
70
+ const newHooks = buildHooks(playScriptPath);
71
+ if (!settings.hooks) {
72
+ settings.hooks = {};
73
+ }
74
+ for (const [event, hookEntries] of Object.entries(newHooks)) {
75
+ if (!settings.hooks[event]) {
76
+ settings.hooks[event] = [];
77
+ }
78
+ settings.hooks[event].push(...hookEntries);
79
+ }
80
+ writeFileSync(settingsPath, `${JSON.stringify(settings, null, 2)}\n`, 'utf-8');
81
+ }
82
+ /**
83
+ * Remove all dota2-hero-sounds hooks from ~/.claude/settings.json.
84
+ */
85
+ export function uninstallClaudeHooks() {
86
+ const settingsPath = getClaudeSettingsPath();
87
+ if (!existsSync(settingsPath)) {
88
+ return;
89
+ }
90
+ const raw = readFileSync(settingsPath, 'utf-8');
91
+ const settings = JSON.parse(raw);
92
+ if (!settings.hooks) {
93
+ return;
94
+ }
95
+ for (const event of Object.keys(settings.hooks)) {
96
+ settings.hooks[event] = settings.hooks[event].filter((entry) => !entry.hooks.some((h) => h.command.includes(HOOK_MARKER)));
97
+ if (settings.hooks[event].length === 0) {
98
+ delete settings.hooks[event];
99
+ }
100
+ }
101
+ // Remove hooks key entirely if empty
102
+ if (Object.keys(settings.hooks).length === 0) {
103
+ delete settings.hooks;
104
+ }
105
+ writeFileSync(settingsPath, `${JSON.stringify(settings, null, 2)}\n`, 'utf-8');
106
+ }
package/dist/cli.d.ts ADDED
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env node
2
+ import { Command } from 'commander';
3
+ declare const program: Command;
4
+ export { program };
package/dist/cli.js ADDED
@@ -0,0 +1,229 @@
1
+ #!/usr/bin/env node
2
+ import { Command } from 'commander';
3
+ import { getClaudeSettingsPath, installClaudeHooks, isClaudeCodeAvailable, uninstallClaudeHooks, } from './claude-hooks.js';
4
+ import { readConfig, writeConfig } from './config.js';
5
+ import { filterSoundsByHeroes, getAvailableHeroes } from './heroes.js';
6
+ import { copyRuntimeFiles, getInstalledPiExtensionDir, getInstalledPlayScript, getInstalledSoundsDir, removeRuntimeFiles, } from './install-files.js';
7
+ import { getOpenCodePluginPath, installOpenCodePlugin, isOpenCodeAvailable, uninstallOpenCodePlugin, } from './opencode-plugin.js';
8
+ import { getPiExtensionPath, installPiExtension, isPiAvailable, uninstallPiExtension, } from './pi-extension.js';
9
+ import { CATEGORIES, listSounds, playSound } from './play-sound.js';
10
+ // ── Helpers ──────────────────────────────────────────────────────────
11
+ function sleep(ms) {
12
+ return new Promise((resolve) => setTimeout(resolve, ms));
13
+ }
14
+ // ── Program ──────────────────────────────────────────────────────────
15
+ const program = new Command();
16
+ program
17
+ .name('dota2-hero-sounds')
18
+ .description('Dota 2 hero voice notifications for Claude Code, OpenCode, and Pi')
19
+ .version('1.0.0');
20
+ // ── install ──────────────────────────────────────────────────────────
21
+ program
22
+ .command('install')
23
+ .description('Install hooks/plugins for detected tools')
24
+ .option('--claude', 'Install Claude Code hooks only')
25
+ .option('--opencode', 'Install OpenCode plugin only')
26
+ .option('--pi', 'Install Pi coding agent extension only')
27
+ .option('--all', 'Install for all supported tools')
28
+ .action(async (opts) => {
29
+ const wantClaude = opts.claude || opts.all;
30
+ const wantOpenCode = opts.opencode || opts.all;
31
+ const wantPi = opts.pi || opts.all;
32
+ const autoDetect = !wantClaude && !wantOpenCode && !wantPi;
33
+ let installedAny = false;
34
+ // Copy runtime files to permanent location first
35
+ copyRuntimeFiles();
36
+ const playScriptPath = getInstalledPlayScript();
37
+ const soundsDir = getInstalledSoundsDir();
38
+ // Claude Code
39
+ const claudeAvailable = isClaudeCodeAvailable();
40
+ const shouldInstallClaude = wantClaude || (autoDetect && claudeAvailable);
41
+ if (shouldInstallClaude) {
42
+ if (!claudeAvailable) {
43
+ console.error('Error: Claude Code config directory (~/.claude/) not found. Is Claude Code installed?');
44
+ }
45
+ else {
46
+ installClaudeHooks(playScriptPath);
47
+ console.log('[+] Claude Code hooks installed');
48
+ console.log(` Config: ${getClaudeSettingsPath()}`);
49
+ installedAny = true;
50
+ }
51
+ }
52
+ // OpenCode
53
+ const openCodeAvailable = isOpenCodeAvailable();
54
+ const shouldInstallOpenCode = wantOpenCode || (autoDetect && openCodeAvailable);
55
+ if (shouldInstallOpenCode) {
56
+ if (!openCodeAvailable) {
57
+ console.error('Error: OpenCode config directory (~/.config/opencode/) not found. Is OpenCode installed?');
58
+ }
59
+ else {
60
+ installOpenCodePlugin(soundsDir);
61
+ console.log('[+] OpenCode plugin installed');
62
+ console.log(` Plugin: ${getOpenCodePluginPath()}`);
63
+ installedAny = true;
64
+ }
65
+ }
66
+ // Pi
67
+ const piAvailable = isPiAvailable();
68
+ const shouldInstallPi = wantPi || (autoDetect && piAvailable);
69
+ if (shouldInstallPi) {
70
+ if (!piAvailable) {
71
+ console.error('Error: Pi config directory (~/.pi/agent/) not found. Is Pi installed?');
72
+ }
73
+ else {
74
+ installPiExtension(getInstalledPiExtensionDir());
75
+ console.log('[+] Pi extension installed');
76
+ console.log(` Extension: ${getPiExtensionPath()}`);
77
+ installedAny = true;
78
+ }
79
+ }
80
+ if (!installedAny) {
81
+ console.log('No supported tools detected. Use --claude, --opencode, or --pi to force install.');
82
+ console.log('');
83
+ console.log('Supported tools:');
84
+ console.log(' Claude Code (~/.claude/)');
85
+ console.log(' OpenCode (~/.config/opencode/)');
86
+ console.log(' Pi (~/.pi/agent/)');
87
+ process.exitCode = 1;
88
+ return;
89
+ }
90
+ console.log('');
91
+ console.log('Dota 2 Axe is ready. Good luck, have fun!');
92
+ });
93
+ // ── uninstall ────────────────────────────────────────────────────────
94
+ program
95
+ .command('uninstall')
96
+ .description('Remove all hooks and plugins')
97
+ .option('--claude', 'Remove Claude Code hooks only')
98
+ .option('--opencode', 'Remove OpenCode plugin only')
99
+ .option('--pi', 'Remove Pi extension only')
100
+ .action((opts) => {
101
+ const removeAll = !opts.claude && !opts.opencode && !opts.pi;
102
+ if (removeAll || opts.claude) {
103
+ uninstallClaudeHooks();
104
+ console.log('[-] Claude Code hooks removed');
105
+ }
106
+ if (removeAll || opts.opencode) {
107
+ uninstallOpenCodePlugin();
108
+ console.log('[-] OpenCode plugin removed');
109
+ }
110
+ if (removeAll || opts.pi) {
111
+ uninstallPiExtension();
112
+ console.log('[-] Pi extension removed');
113
+ }
114
+ if (removeAll) {
115
+ removeRuntimeFiles();
116
+ console.log('[-] Runtime files removed');
117
+ }
118
+ console.log('');
119
+ console.log('Axe is not Axe! (sounds removed)');
120
+ });
121
+ // ── test ─────────────────────────────────────────────────────────────
122
+ program
123
+ .command('test')
124
+ .description('Play one sound from each category')
125
+ .argument('[category]', 'Play a specific category only')
126
+ .action(async (category) => {
127
+ if (category) {
128
+ if (!listSounds()[category]) {
129
+ console.error(`Unknown category: ${category}`);
130
+ console.error(`Available: ${[...CATEGORIES].join(', ')}`);
131
+ process.exitCode = 1;
132
+ return;
133
+ }
134
+ console.log(`Playing: ${category}`);
135
+ playSound(category);
136
+ return;
137
+ }
138
+ console.log('Testing all sound categories...\n');
139
+ for (const cat of [...CATEGORIES]) {
140
+ console.log(` Playing: ${cat}`);
141
+ playSound(cat);
142
+ await sleep(2000);
143
+ }
144
+ console.log('\nDone. If you heard Axe, everything is working.');
145
+ });
146
+ // ── list ─────────────────────────────────────────────────────────────
147
+ program
148
+ .command('list')
149
+ .description('Show all available sounds by category')
150
+ .action(() => {
151
+ const config = readConfig();
152
+ const allSounds = listSounds();
153
+ if (config.heroes.length > 0) {
154
+ console.log(`Dota 2 Sound Categories (filtered: ${config.heroes.join(', ')})\n`);
155
+ }
156
+ else {
157
+ console.log('Dota 2 Sound Categories\n');
158
+ }
159
+ for (const [cat, sounds] of Object.entries(allSounds)) {
160
+ const filtered = config.heroes.length > 0 ? filterSoundsByHeroes(sounds, config.heroes) : sounds;
161
+ console.log(` ${cat}: (${filtered.length} sounds)`);
162
+ for (const sound of filtered) {
163
+ const name = sound.replace(/^.*\//, '').replace('.mp3', '');
164
+ console.log(` - ${name}`);
165
+ }
166
+ console.log('');
167
+ }
168
+ });
169
+ // ── hero ─────────────────────────────────────────────────────────────
170
+ const hero = program.command('hero').description('Manage hero preferences');
171
+ hero
172
+ .command('set')
173
+ .description('Set preferred heroes')
174
+ .argument('<heroes...>', 'Hero keys (e.g., axe pudge lina)')
175
+ .action((heroes) => {
176
+ const available = getAvailableHeroes();
177
+ const validKeys = new Set(available.map((h) => h.key));
178
+ const invalid = heroes.filter((h) => !validKeys.has(h));
179
+ if (invalid.length > 0) {
180
+ console.error(`Unknown hero(es): ${invalid.join(', ')}`);
181
+ console.error(`Run 'dota2-hero-sounds hero list' to see available heroes`);
182
+ process.exitCode = 1;
183
+ return;
184
+ }
185
+ writeConfig({ heroes });
186
+ console.log(`Heroes set: ${heroes.join(', ')}`);
187
+ });
188
+ hero
189
+ .command('list')
190
+ .description('Show available heroes with sound counts')
191
+ .action(() => {
192
+ const heroes = getAvailableHeroes();
193
+ const config = readConfig();
194
+ const selected = new Set(config.heroes);
195
+ console.log('Available Heroes\n');
196
+ console.log(` ${'Hero'.padEnd(20)} ${'Success'.padEnd(9)} ${'Error'.padEnd(9)} ${'Attention'.padEnd(11)} ${'Start'.padEnd(9)} Total`);
197
+ console.log(` ${'─'.repeat(20)} ${'─'.repeat(9)} ${'─'.repeat(9)} ${'─'.repeat(11)} ${'─'.repeat(9)} ${'─'.repeat(5)}`);
198
+ for (const h of heroes) {
199
+ const marker = selected.has(h.key) ? ' *' : '';
200
+ console.log(` ${(h.key + marker).padEnd(20)} ${String(h.counts.success).padEnd(9)} ${String(h.counts.error).padEnd(9)} ${String(h.counts.attention).padEnd(11)} ${String(h.counts.start).padEnd(9)} ${h.total}`);
201
+ }
202
+ if (selected.size > 0) {
203
+ console.log(`\n * = selected`);
204
+ }
205
+ });
206
+ hero
207
+ .command('show')
208
+ .description('Show current hero preference')
209
+ .action(() => {
210
+ const config = readConfig();
211
+ if (config.heroes.length === 0) {
212
+ console.log('No hero preference set (using all heroes)');
213
+ }
214
+ else {
215
+ console.log(`Current heroes: ${config.heroes.join(', ')}`);
216
+ }
217
+ });
218
+ hero
219
+ .command('clear')
220
+ .description('Clear hero preference (use all heroes)')
221
+ .action(() => {
222
+ writeConfig({ heroes: [] });
223
+ console.log('Hero preference cleared (using all heroes)');
224
+ });
225
+ // ── parse ────────────────────────────────────────────────────────────
226
+ export { program };
227
+ if (!process.env['VITEST']) {
228
+ program.parse();
229
+ }
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Get the path to Codex's config file.
3
+ */
4
+ export declare function getCodexConfigPath(): string;
5
+ /**
6
+ * Get the path to Codex's legacy hooks file.
7
+ */
8
+ export declare function getCodexHooksPath(): string;
9
+ /**
10
+ * Check if Codex config directory exists.
11
+ */
12
+ export declare function isCodexAvailable(): boolean;
13
+ /**
14
+ * Install Codex notifications into ~/.codex/config.toml.
15
+ * Current Codex exposes only the external notify command and only emits
16
+ * agent-turn-complete, so we install a single notify handler for success sounds.
17
+ */
18
+ export declare function installCodexNotify(playScriptPath: string): void;
19
+ /**
20
+ * Remove all dota2-code-sounds Codex config from config.toml and clean up
21
+ * legacy hooks.json installs from older versions.
22
+ */
23
+ export declare function uninstallCodexNotify(): void;