pingthings 0.4.0 → 0.6.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.
- package/README.md +12 -0
- package/bin/pingthings.js +17 -0
- package/package.json +1 -1
- package/packs/0ad-civilizations/manifest.json +56 -56
- package/packs/0ad-civilizations/sounds/alarm-alert.ogg +0 -0
- package/packs/0ad-civilizations/sounds/alarm-attack.ogg +0 -0
- package/packs/0ad-civilizations/sounds/alarm-defeat.ogg +0 -0
- package/packs/0ad-civilizations/sounds/alarm-no-resource.ogg +0 -0
- package/packs/0ad-civilizations/sounds/alarm-objective.ogg +0 -0
- package/packs/0ad-civilizations/sounds/alarm-research-complete.ogg +0 -0
- package/packs/0ad-civilizations/sounds/alarm-victory.ogg +0 -0
- package/packs/0ad-civilizations/sounds/greek-as-you-wish.ogg +0 -0
- package/packs/0ad-civilizations/sounds/greek-attack-1.ogg +0 -0
- package/packs/0ad-civilizations/sounds/greek-build-1.ogg +0 -0
- package/packs/0ad-civilizations/sounds/greek-heal-1.ogg +0 -0
- package/packs/0ad-civilizations/sounds/greek-march-1.ogg +0 -0
- package/packs/0ad-civilizations/sounds/greek-my-lord-1.ogg +0 -0
- package/packs/0ad-civilizations/sounds/greek-my-lord-2.ogg +0 -0
- package/packs/0ad-civilizations/sounds/greek-retreat-1.ogg +0 -0
- package/packs/0ad-civilizations/sounds/greek-what-is-it-1.ogg +0 -0
- package/packs/0ad-civilizations/sounds/greek-yes.ogg +0 -0
- package/packs/0ad-civilizations/sounds/latin-attack-1.ogg +0 -0
- package/packs/0ad-civilizations/sounds/latin-build-1.ogg +0 -0
- package/packs/0ad-civilizations/sounds/latin-fight-1.ogg +0 -0
- package/packs/0ad-civilizations/sounds/latin-heal-1.ogg +0 -0
- package/packs/0ad-civilizations/sounds/latin-hello-1.ogg +0 -0
- package/packs/0ad-civilizations/sounds/latin-my-lord-1.ogg +0 -0
- package/packs/0ad-civilizations/sounds/latin-what-is-it.ogg +0 -0
- package/packs/0ad-civilizations/sounds/persian-attack-1.ogg +0 -0
- package/packs/0ad-civilizations/sounds/persian-by-your-order.ogg +0 -0
- package/packs/0ad-civilizations/sounds/persian-forward-1.ogg +0 -0
- package/packs/0ad-civilizations/sounds/persian-i-will-go.ogg +0 -0
- package/packs/7kaa-soldiers/manifest.json +90 -90
- package/packs/7kaa-soldiers/sounds/00001-CH_A2.ogg +0 -0
- package/packs/7kaa-soldiers/sounds/00006-NO_V2.ogg +0 -0
- package/packs/7kaa-soldiers/sounds/00007-NO_V3.ogg +0 -0
- package/packs/7kaa-soldiers/sounds/00008-MA_V1.ogg +0 -0
- package/packs/7kaa-soldiers/sounds/00009-GR_V2.ogg +0 -0
- package/packs/7kaa-soldiers/sounds/00010-GR_V3.ogg +0 -0
- package/packs/7kaa-soldiers/sounds/00011-VI_V1.ogg +0 -0
- package/packs/7kaa-soldiers/sounds/00012-NO_A1.ogg +0 -0
- package/packs/7kaa-soldiers/sounds/00012-VI_V2.ogg +0 -0
- package/packs/7kaa-soldiers/sounds/00013-GR_V1.ogg +0 -0
- package/packs/7kaa-soldiers/sounds/00013-NO_A2.ogg +0 -0
- package/packs/7kaa-soldiers/sounds/00014-MA_A1.ogg +0 -0
- package/packs/7kaa-soldiers/sounds/00014-PE_V1.ogg +0 -0
- package/packs/7kaa-soldiers/sounds/00015-GR_A1.ogg +0 -0
- package/packs/7kaa-soldiers/sounds/00015-MA_V2.ogg +0 -0
- package/packs/7kaa-soldiers/sounds/00016-MA_V3.ogg +0 -0
- package/packs/7kaa-soldiers/sounds/00016-VI_A1.ogg +0 -0
- package/packs/7kaa-soldiers/sounds/00017-MA_V4.ogg +0 -0
- package/packs/7kaa-soldiers/sounds/00017-VI_A2.ogg +0 -0
- package/packs/7kaa-soldiers/sounds/00018-PE_A2.ogg +0 -0
- package/packs/7kaa-soldiers/sounds/00018-PE_V2.ogg +0 -0
- package/packs/7kaa-soldiers/sounds/00019-PE_V3.ogg +0 -0
- package/packs/7kaa-soldiers/sounds/00020-PE_A1.ogg +0 -0
- package/packs/7kaa-soldiers/sounds/00020-PE_V4.ogg +0 -0
- package/packs/7kaa-soldiers/sounds/00021-CH_A1.ogg +0 -0
- package/packs/7kaa-soldiers/sounds/00021-CH_V1.ogg +0 -0
- package/packs/7kaa-soldiers/sounds/00022-CH_V2.ogg +0 -0
- package/packs/7kaa-soldiers/sounds/00022-JA_A1.ogg +0 -0
- package/packs/7kaa-soldiers/sounds/00023-CH_V3.ogg +0 -0
- package/packs/7kaa-soldiers/sounds/00023-JA_A2.ogg +0 -0
- package/packs/7kaa-soldiers/sounds/00024-CH_V4.ogg +0 -0
- package/packs/7kaa-soldiers/sounds/00025-CH_V5.ogg +0 -0
- package/packs/7kaa-soldiers/sounds/00026-JA_V1.ogg +0 -0
- package/packs/7kaa-soldiers/sounds/00027-JA_V2.ogg +0 -0
- package/packs/7kaa-soldiers/sounds/00028-JA_V3.ogg +0 -0
- package/packs/7kaa-soldiers/sounds/00029-JA_V4.ogg +0 -0
- package/packs/7kaa-soldiers/sounds/00030-JA_V5.ogg +0 -0
- package/packs/7kaa-soldiers/sounds/00035-MA_V5.ogg +0 -0
- package/packs/7kaa-soldiers/sounds/00083-READY.ogg +0 -0
- package/packs/7kaa-soldiers/sounds/00084-NO_V1.ogg +0 -0
- package/packs/7kaa-soldiers/sounds/00085-EG_V1.ogg +0 -0
- package/packs/7kaa-soldiers/sounds/00086-EG_V2.ogg +0 -0
- package/packs/7kaa-soldiers/sounds/00087-EG_V3.ogg +0 -0
- package/packs/7kaa-soldiers/sounds/00088-EG_V4.ogg +0 -0
- package/packs/7kaa-soldiers/sounds/00089-IN_V1.ogg +0 -0
- package/packs/7kaa-soldiers/sounds/00090-IN_V2.ogg +0 -0
- package/packs/7kaa-soldiers/sounds/00091-IN_V3.ogg +0 -0
- package/packs/7kaa-soldiers/sounds/00092-IN_V4.ogg +0 -0
- package/packs/7kaa-soldiers/sounds/00093-ZU_V2.ogg +0 -0
- package/packs/7kaa-soldiers/sounds/00094-ZU_V3.ogg +0 -0
- package/packs/7kaa-soldiers/sounds/00095-ZU_V5.ogg +0 -0
- package/packs/7kaa-soldiers/sounds/00096-ZU_V7.ogg +0 -0
- package/packs/7kaa-soldiers/sounds/00097-ZU_V8.ogg +0 -0
- package/packs/fighting-announcer/manifest.json +62 -0
- package/packs/fighting-announcer/sounds/begin.ogg +0 -0
- package/packs/fighting-announcer/sounds/complete.ogg +0 -0
- package/packs/fighting-announcer/sounds/congratulations.ogg +0 -0
- package/packs/fighting-announcer/sounds/defeat.ogg +0 -0
- package/packs/fighting-announcer/sounds/failure.ogg +0 -0
- package/packs/fighting-announcer/sounds/fight.ogg +0 -0
- package/packs/fighting-announcer/sounds/final-round.ogg +0 -0
- package/packs/fighting-announcer/sounds/finish.ogg +0 -0
- package/packs/fighting-announcer/sounds/game-over.ogg +0 -0
- package/packs/fighting-announcer/sounds/get-set.ogg +0 -0
- package/packs/fighting-announcer/sounds/go.ogg +0 -0
- package/packs/fighting-announcer/sounds/great.ogg +0 -0
- package/packs/fighting-announcer/sounds/high-score.ogg +0 -0
- package/packs/fighting-announcer/sounds/new-record.ogg +0 -0
- package/packs/fighting-announcer/sounds/no-contest.ogg +0 -0
- package/packs/fighting-announcer/sounds/ready.ogg +0 -0
- package/packs/fighting-announcer/sounds/sudden-death.ogg +0 -0
- package/packs/fighting-announcer/sounds/victory.ogg +0 -0
- package/packs/fighting-announcer/sounds/you-lose.ogg +0 -0
- package/packs/fighting-announcer/sounds/you-win.ogg +0 -0
- package/packs/freedoom-arsenal/manifest.json +36 -36
- package/packs/freedoom-arsenal/sounds/dsbarexp.ogg +0 -0
- package/packs/freedoom-arsenal/sounds/dsbfg.ogg +0 -0
- package/packs/freedoom-arsenal/sounds/dsdoropn.ogg +0 -0
- package/packs/freedoom-arsenal/sounds/dsdshtgn.ogg +0 -0
- package/packs/freedoom-arsenal/sounds/dsgetpow.ogg +0 -0
- package/packs/freedoom-arsenal/sounds/dsitemup.ogg +0 -0
- package/packs/freedoom-arsenal/sounds/dsoof.ogg +0 -0
- package/packs/freedoom-arsenal/sounds/dspistol.ogg +0 -0
- package/packs/freedoom-arsenal/sounds/dsplasma.ogg +0 -0
- package/packs/freedoom-arsenal/sounds/dspldeth.ogg +0 -0
- package/packs/freedoom-arsenal/sounds/dspunch.ogg +0 -0
- package/packs/freedoom-arsenal/sounds/dsrlaunc.ogg +0 -0
- package/packs/freedoom-arsenal/sounds/dsrxplod.ogg +0 -0
- package/packs/freedoom-arsenal/sounds/dssawup.ogg +0 -0
- package/packs/freedoom-arsenal/sounds/dssgcock.ogg +0 -0
- package/packs/freedoom-arsenal/sounds/dsshotgn.ogg +0 -0
- package/packs/freedoom-arsenal/sounds/dsswtchn.ogg +0 -0
- package/packs/freedoom-arsenal/sounds/dstelept.ogg +0 -0
- package/packs/freedoom-arsenal/sounds/dswpnup.ogg +0 -0
- package/packs/kenney-interface/manifest.json +36 -36
- package/packs/kenney-interface/sounds/back-1.ogg +0 -0
- package/packs/kenney-interface/sounds/bong.ogg +0 -0
- package/packs/kenney-interface/sounds/click-1.ogg +0 -0
- package/packs/kenney-interface/sounds/close-1.ogg +0 -0
- package/packs/kenney-interface/sounds/confirmation-1.ogg +0 -0
- package/packs/kenney-interface/sounds/confirmation-2.ogg +0 -0
- package/packs/kenney-interface/sounds/confirmation-3.ogg +0 -0
- package/packs/kenney-interface/sounds/error-1.ogg +0 -0
- package/packs/kenney-interface/sounds/error-2.ogg +0 -0
- package/packs/kenney-interface/sounds/error-3.ogg +0 -0
- package/packs/kenney-interface/sounds/glitch-1.ogg +0 -0
- package/packs/kenney-interface/sounds/maximize-1.ogg +0 -0
- package/packs/kenney-interface/sounds/maximize-2.ogg +0 -0
- package/packs/kenney-interface/sounds/open-1.ogg +0 -0
- package/packs/kenney-interface/sounds/pluck-1.ogg +0 -0
- package/packs/kenney-interface/sounds/question-1.ogg +0 -0
- package/packs/kenney-interface/sounds/question-2.ogg +0 -0
- package/packs/kenney-interface/sounds/question-3.ogg +0 -0
- package/packs/kenney-scifi/manifest.json +36 -36
- package/packs/kenney-scifi/sounds/computer-1.ogg +0 -0
- package/packs/kenney-scifi/sounds/computer-2.ogg +0 -0
- package/packs/kenney-scifi/sounds/computer-3.ogg +0 -0
- package/packs/kenney-scifi/sounds/door-close.ogg +0 -0
- package/packs/kenney-scifi/sounds/door-open.ogg +0 -0
- package/packs/kenney-scifi/sounds/engine-1.ogg +0 -0
- package/packs/kenney-scifi/sounds/explosion-1.ogg +0 -0
- package/packs/kenney-scifi/sounds/explosion-2.ogg +0 -0
- package/packs/kenney-scifi/sounds/forcefield-1.ogg +0 -0
- package/packs/kenney-scifi/sounds/forcefield-2.ogg +0 -0
- package/packs/kenney-scifi/sounds/impact-1.ogg +0 -0
- package/packs/kenney-scifi/sounds/impact-2.ogg +0 -0
- package/packs/kenney-scifi/sounds/laser-large.ogg +0 -0
- package/packs/kenney-scifi/sounds/laser-retro.ogg +0 -0
- package/packs/kenney-scifi/sounds/low-explosion.ogg +0 -0
- package/packs/kenney-scifi/sounds/slime.ogg +0 -0
- package/packs/kenney-scifi/sounds/thruster-1.ogg +0 -0
- package/packs/kenney-scifi/sounds/thruster-2.ogg +0 -0
- package/packs/openarena-announcer/manifest.json +33 -33
- package/packs/openarena-announcer/sounds/accuracy.ogg +0 -0
- package/packs/openarena-announcer/sounds/assist.ogg +0 -0
- package/packs/openarena-announcer/sounds/defense.ogg +0 -0
- package/packs/openarena-announcer/sounds/denied.ogg +0 -0
- package/packs/openarena-announcer/sounds/excellent.ogg +0 -0
- package/packs/openarena-announcer/sounds/fight.ogg +0 -0
- package/packs/openarena-announcer/sounds/gauntlet.ogg +0 -0
- package/packs/openarena-announcer/sounds/humiliation.ogg +0 -0
- package/packs/openarena-announcer/sounds/impressive.ogg +0 -0
- package/packs/openarena-announcer/sounds/one.ogg +0 -0
- package/packs/openarena-announcer/sounds/perfect.ogg +0 -0
- package/packs/openarena-announcer/sounds/prepare.ogg +0 -0
- package/packs/openarena-announcer/sounds/sudden_death.ogg +0 -0
- package/packs/openarena-announcer/sounds/takenlead.ogg +0 -0
- package/packs/openarena-announcer/sounds/three.ogg +0 -0
- package/packs/openarena-announcer/sounds/two.ogg +0 -0
- package/packs/openarena-announcer/sounds/voc_holyshit.ogg +0 -0
- package/packs/openarena-announcer/sounds/youwin.ogg +0 -0
- package/packs/retro-8bit/manifest.json +36 -36
- package/packs/retro-8bit/sounds/button-1.ogg +0 -0
- package/packs/retro-8bit/sounds/button-2.ogg +0 -0
- package/packs/retro-8bit/sounds/button-3.ogg +0 -0
- package/packs/retro-8bit/sounds/coin-1.ogg +0 -0
- package/packs/retro-8bit/sounds/coin-2.ogg +0 -0
- package/packs/retro-8bit/sounds/coin-cluster.ogg +0 -0
- package/packs/retro-8bit/sounds/coin-double.ogg +0 -0
- package/packs/retro-8bit/sounds/damage-1.ogg +0 -0
- package/packs/retro-8bit/sounds/error-1.ogg +0 -0
- package/packs/retro-8bit/sounds/error-2.ogg +0 -0
- package/packs/retro-8bit/sounds/error-3.ogg +0 -0
- package/packs/retro-8bit/sounds/fanfare-1.ogg +0 -0
- package/packs/retro-8bit/sounds/fanfare-2.ogg +0 -0
- package/packs/retro-8bit/sounds/fanfare-3.ogg +0 -0
- package/packs/retro-8bit/sounds/negative-1.ogg +0 -0
- package/packs/retro-8bit/sounds/negative-2.ogg +0 -0
- package/packs/retro-8bit/sounds/powerup-1.ogg +0 -0
- package/packs/retro-8bit/sounds/powerup-2.ogg +0 -0
- package/packs/warzone2100-command/manifest.json +42 -42
- package/packs/warzone2100-command/sounds/construction-completed.ogg +0 -0
- package/packs/warzone2100-command/sounds/design-completed.ogg +0 -0
- package/packs/warzone2100-command/sounds/enemy-detected.ogg +0 -0
- package/packs/warzone2100-command/sounds/incoming-enemy-transport.ogg +0 -0
- package/packs/warzone2100-command/sounds/incoming-transmission.ogg +0 -0
- package/packs/warzone2100-command/sounds/major-research-completed.ogg +0 -0
- package/packs/warzone2100-command/sounds/mission-failed.ogg +0 -0
- package/packs/warzone2100-command/sounds/mission-objective.ogg +0 -0
- package/packs/warzone2100-command/sounds/mission-successful.ogg +0 -0
- package/packs/warzone2100-command/sounds/mission-update.ogg +0 -0
- package/packs/warzone2100-command/sounds/new-research-available.ogg +0 -0
- package/packs/warzone2100-command/sounds/nexus-laugh1.ogg +0 -0
- package/packs/warzone2100-command/sounds/nexus-laugh2.ogg +0 -0
- package/packs/warzone2100-command/sounds/power-low.ogg +0 -0
- package/packs/warzone2100-command/sounds/production-cancelled.ogg +0 -0
- package/packs/warzone2100-command/sounds/production-completed.ogg +0 -0
- package/packs/warzone2100-command/sounds/reinforcements-available.ogg +0 -0
- package/packs/warzone2100-command/sounds/research-completed.ogg +0 -0
- package/packs/warzone2100-command/sounds/retreat-heavy-damage.ogg +0 -0
- package/packs/warzone2100-command/sounds/structure-under-attack.ogg +0 -0
- package/packs/warzone2100-command/sounds/unit-repaired.ogg +0 -0
- package/packs/wesnoth-combat/manifest.json +38 -38
- package/packs/wesnoth-combat/sounds/axe.ogg +0 -0
- package/packs/wesnoth-combat/sounds/bow.ogg +0 -0
- package/packs/wesnoth-combat/sounds/crossbow.ogg +0 -0
- package/packs/wesnoth-combat/sounds/dwarf-laugh.ogg +0 -0
- package/packs/wesnoth-combat/sounds/explosion.ogg +0 -0
- package/packs/wesnoth-combat/sounds/fanfare-short.ogg +0 -0
- package/packs/wesnoth-combat/sounds/flame-big.ogg +0 -0
- package/packs/wesnoth-combat/sounds/gold.ogg +0 -0
- package/packs/wesnoth-combat/sounds/gryphon-shriek-1.ogg +0 -0
- package/packs/wesnoth-combat/sounds/hatchet.ogg +0 -0
- package/packs/wesnoth-combat/sounds/heal.ogg +0 -0
- package/packs/wesnoth-combat/sounds/lightning.ogg +0 -0
- package/packs/wesnoth-combat/sounds/magic-dark.ogg +0 -0
- package/packs/wesnoth-combat/sounds/magic-holy-1.ogg +0 -0
- package/packs/wesnoth-combat/sounds/magic-missile-1.ogg +0 -0
- package/packs/wesnoth-combat/sounds/open-chest.ogg +0 -0
- package/packs/wesnoth-combat/sounds/potion.ogg +0 -0
- package/packs/wesnoth-combat/sounds/sword-1.ogg +0 -0
- package/packs/wesnoth-combat/sounds/wolf-growl-1.ogg +0 -0
- package/packs/xonotic-announcer/manifest.json +52 -0
- package/packs/xonotic-announcer/sounds/1fragleft.ogg +0 -0
- package/packs/xonotic-announcer/sounds/airshot.ogg +0 -0
- package/packs/xonotic-announcer/sounds/amazing.ogg +0 -0
- package/packs/xonotic-announcer/sounds/awesome.ogg +0 -0
- package/packs/xonotic-announcer/sounds/begin.ogg +0 -0
- package/packs/xonotic-announcer/sounds/botlike.ogg +0 -0
- package/packs/xonotic-announcer/sounds/electrobitch.ogg +0 -0
- package/packs/xonotic-announcer/sounds/headshot.ogg +0 -0
- package/packs/xonotic-announcer/sounds/impressive.ogg +0 -0
- package/packs/xonotic-announcer/sounds/lastsecond.ogg +0 -0
- package/packs/xonotic-announcer/sounds/leadgained.ogg +0 -0
- package/packs/xonotic-announcer/sounds/narrowly.ogg +0 -0
- package/packs/xonotic-announcer/sounds/prepareforbattle.ogg +0 -0
- package/packs/xonotic-announcer/sounds/terminated.ogg +0 -0
- package/packs/xonotic-announcer/sounds/yoda.ogg +0 -0
- package/src/cli/completions.js +182 -0
- package/src/cli/config.js +32 -3
- package/src/cli/create.js +1 -1
- package/src/cli/doctor.js +134 -0
- package/src/cli/first-run.js +59 -0
- package/src/cli/init.js +11 -8
- package/src/cli/play.js +32 -2
- package/src/cli/random-pack.js +44 -0
- package/src/cli/select.js +36 -32
- package/src/cli/uninstall.js +5 -0
- package/src/cli/update.js +43 -0
- package/src/config.js +35 -0
- package/src/notify.js +19 -0
- package/src/player.js +17 -12
- package/packs/0ad-civilizations/sounds/alarm-alert.wav +0 -0
- package/packs/0ad-civilizations/sounds/alarm-attack.wav +0 -0
- package/packs/0ad-civilizations/sounds/alarm-defeat.wav +0 -0
- package/packs/0ad-civilizations/sounds/alarm-no-resource.wav +0 -0
- package/packs/0ad-civilizations/sounds/alarm-objective.wav +0 -0
- package/packs/0ad-civilizations/sounds/alarm-research-complete.wav +0 -0
- package/packs/0ad-civilizations/sounds/alarm-victory.wav +0 -0
- package/packs/0ad-civilizations/sounds/greek-as-you-wish.wav +0 -0
- package/packs/0ad-civilizations/sounds/greek-attack-1.wav +0 -0
- package/packs/0ad-civilizations/sounds/greek-build-1.wav +0 -0
- package/packs/0ad-civilizations/sounds/greek-heal-1.wav +0 -0
- package/packs/0ad-civilizations/sounds/greek-march-1.wav +0 -0
- package/packs/0ad-civilizations/sounds/greek-my-lord-1.wav +0 -0
- package/packs/0ad-civilizations/sounds/greek-my-lord-2.wav +0 -0
- package/packs/0ad-civilizations/sounds/greek-retreat-1.wav +0 -0
- package/packs/0ad-civilizations/sounds/greek-what-is-it-1.wav +0 -0
- package/packs/0ad-civilizations/sounds/greek-yes.wav +0 -0
- package/packs/0ad-civilizations/sounds/latin-attack-1.wav +0 -0
- package/packs/0ad-civilizations/sounds/latin-build-1.wav +0 -0
- package/packs/0ad-civilizations/sounds/latin-fight-1.wav +0 -0
- package/packs/0ad-civilizations/sounds/latin-heal-1.wav +0 -0
- package/packs/0ad-civilizations/sounds/latin-hello-1.wav +0 -0
- package/packs/0ad-civilizations/sounds/latin-my-lord-1.wav +0 -0
- package/packs/0ad-civilizations/sounds/latin-what-is-it.wav +0 -0
- package/packs/0ad-civilizations/sounds/persian-attack-1.wav +0 -0
- package/packs/0ad-civilizations/sounds/persian-by-your-order.wav +0 -0
- package/packs/0ad-civilizations/sounds/persian-forward-1.wav +0 -0
- package/packs/0ad-civilizations/sounds/persian-i-will-go.wav +0 -0
- package/packs/7kaa-soldiers/sounds/00001-CH_A2.wav +0 -0
- package/packs/7kaa-soldiers/sounds/00006-NO_V2.wav +0 -0
- package/packs/7kaa-soldiers/sounds/00007-NO_V3.wav +0 -0
- package/packs/7kaa-soldiers/sounds/00008-MA_V1.wav +0 -0
- package/packs/7kaa-soldiers/sounds/00009-GR_V2.wav +0 -0
- package/packs/7kaa-soldiers/sounds/00010-GR_V3.wav +0 -0
- package/packs/7kaa-soldiers/sounds/00011-VI_V1.wav +0 -0
- package/packs/7kaa-soldiers/sounds/00012-NO_A1.wav +0 -0
- package/packs/7kaa-soldiers/sounds/00012-VI_V2.wav +0 -0
- package/packs/7kaa-soldiers/sounds/00013-GR_V1.wav +0 -0
- package/packs/7kaa-soldiers/sounds/00013-NO_A2.wav +0 -0
- package/packs/7kaa-soldiers/sounds/00014-MA_A1.wav +0 -0
- package/packs/7kaa-soldiers/sounds/00014-PE_V1.wav +0 -0
- package/packs/7kaa-soldiers/sounds/00015-GR_A1.wav +0 -0
- package/packs/7kaa-soldiers/sounds/00015-MA_V2.wav +0 -0
- package/packs/7kaa-soldiers/sounds/00016-MA_V3.wav +0 -0
- package/packs/7kaa-soldiers/sounds/00016-VI_A1.wav +0 -0
- package/packs/7kaa-soldiers/sounds/00017-MA_V4.wav +0 -0
- package/packs/7kaa-soldiers/sounds/00017-VI_A2.wav +0 -0
- package/packs/7kaa-soldiers/sounds/00018-PE_A2.wav +0 -0
- package/packs/7kaa-soldiers/sounds/00018-PE_V2.wav +0 -0
- package/packs/7kaa-soldiers/sounds/00019-PE_V3.wav +0 -0
- package/packs/7kaa-soldiers/sounds/00020-PE_A1.wav +0 -0
- package/packs/7kaa-soldiers/sounds/00020-PE_V4.wav +0 -0
- package/packs/7kaa-soldiers/sounds/00021-CH_A1.wav +0 -0
- package/packs/7kaa-soldiers/sounds/00021-CH_V1.wav +0 -0
- package/packs/7kaa-soldiers/sounds/00022-CH_V2.wav +0 -0
- package/packs/7kaa-soldiers/sounds/00022-JA_A1.wav +0 -0
- package/packs/7kaa-soldiers/sounds/00023-CH_V3.wav +0 -0
- package/packs/7kaa-soldiers/sounds/00023-JA_A2.wav +0 -0
- package/packs/7kaa-soldiers/sounds/00024-CH_V4.wav +0 -0
- package/packs/7kaa-soldiers/sounds/00025-CH_V5.wav +0 -0
- package/packs/7kaa-soldiers/sounds/00026-JA_V1.wav +0 -0
- package/packs/7kaa-soldiers/sounds/00027-JA_V2.wav +0 -0
- package/packs/7kaa-soldiers/sounds/00028-JA_V3.wav +0 -0
- package/packs/7kaa-soldiers/sounds/00029-JA_V4.wav +0 -0
- package/packs/7kaa-soldiers/sounds/00030-JA_V5.wav +0 -0
- package/packs/7kaa-soldiers/sounds/00035-MA_V5.wav +0 -0
- package/packs/7kaa-soldiers/sounds/00083-READY.wav +0 -0
- package/packs/7kaa-soldiers/sounds/00084-NO_V1.wav +0 -0
- package/packs/7kaa-soldiers/sounds/00085-EG_V1.wav +0 -0
- package/packs/7kaa-soldiers/sounds/00086-EG_V2.wav +0 -0
- package/packs/7kaa-soldiers/sounds/00087-EG_V3.wav +0 -0
- package/packs/7kaa-soldiers/sounds/00088-EG_V4.wav +0 -0
- package/packs/7kaa-soldiers/sounds/00089-IN_V1.wav +0 -0
- package/packs/7kaa-soldiers/sounds/00090-IN_V2.wav +0 -0
- package/packs/7kaa-soldiers/sounds/00091-IN_V3.wav +0 -0
- package/packs/7kaa-soldiers/sounds/00092-IN_V4.wav +0 -0
- package/packs/7kaa-soldiers/sounds/00093-ZU_V2.wav +0 -0
- package/packs/7kaa-soldiers/sounds/00094-ZU_V3.wav +0 -0
- package/packs/7kaa-soldiers/sounds/00095-ZU_V5.wav +0 -0
- package/packs/7kaa-soldiers/sounds/00096-ZU_V7.wav +0 -0
- package/packs/7kaa-soldiers/sounds/00097-ZU_V8.wav +0 -0
- package/packs/freedoom-arsenal/sounds/dsbarexp.wav +0 -0
- package/packs/freedoom-arsenal/sounds/dsbfg.wav +0 -0
- package/packs/freedoom-arsenal/sounds/dsdoropn.wav +0 -0
- package/packs/freedoom-arsenal/sounds/dsdshtgn.wav +0 -0
- package/packs/freedoom-arsenal/sounds/dsgetpow.wav +0 -0
- package/packs/freedoom-arsenal/sounds/dsitemup.wav +0 -0
- package/packs/freedoom-arsenal/sounds/dsoof.wav +0 -0
- package/packs/freedoom-arsenal/sounds/dspistol.wav +0 -0
- package/packs/freedoom-arsenal/sounds/dsplasma.wav +0 -0
- package/packs/freedoom-arsenal/sounds/dspldeth.wav +0 -0
- package/packs/freedoom-arsenal/sounds/dspunch.wav +0 -0
- package/packs/freedoom-arsenal/sounds/dsrlaunc.wav +0 -0
- package/packs/freedoom-arsenal/sounds/dsrxplod.wav +0 -0
- package/packs/freedoom-arsenal/sounds/dssawup.wav +0 -0
- package/packs/freedoom-arsenal/sounds/dssgcock.wav +0 -0
- package/packs/freedoom-arsenal/sounds/dsshotgn.wav +0 -0
- package/packs/freedoom-arsenal/sounds/dsswtchn.wav +0 -0
- package/packs/freedoom-arsenal/sounds/dstelept.wav +0 -0
- package/packs/freedoom-arsenal/sounds/dswpnup.wav +0 -0
- package/packs/kenney-interface/sounds/back-1.wav +0 -0
- package/packs/kenney-interface/sounds/bong.wav +0 -0
- package/packs/kenney-interface/sounds/click-1.wav +0 -0
- package/packs/kenney-interface/sounds/close-1.wav +0 -0
- package/packs/kenney-interface/sounds/confirmation-1.wav +0 -0
- package/packs/kenney-interface/sounds/confirmation-2.wav +0 -0
- package/packs/kenney-interface/sounds/confirmation-3.wav +0 -0
- package/packs/kenney-interface/sounds/error-1.wav +0 -0
- package/packs/kenney-interface/sounds/error-2.wav +0 -0
- package/packs/kenney-interface/sounds/error-3.wav +0 -0
- package/packs/kenney-interface/sounds/glitch-1.wav +0 -0
- package/packs/kenney-interface/sounds/maximize-1.wav +0 -0
- package/packs/kenney-interface/sounds/maximize-2.wav +0 -0
- package/packs/kenney-interface/sounds/open-1.wav +0 -0
- package/packs/kenney-interface/sounds/pluck-1.wav +0 -0
- package/packs/kenney-interface/sounds/question-1.wav +0 -0
- package/packs/kenney-interface/sounds/question-2.wav +0 -0
- package/packs/kenney-interface/sounds/question-3.wav +0 -0
- package/packs/kenney-scifi/sounds/computer-1.wav +0 -0
- package/packs/kenney-scifi/sounds/computer-2.wav +0 -0
- package/packs/kenney-scifi/sounds/computer-3.wav +0 -0
- package/packs/kenney-scifi/sounds/door-close.wav +0 -0
- package/packs/kenney-scifi/sounds/door-open.wav +0 -0
- package/packs/kenney-scifi/sounds/engine-1.wav +0 -0
- package/packs/kenney-scifi/sounds/explosion-1.wav +0 -0
- package/packs/kenney-scifi/sounds/explosion-2.wav +0 -0
- package/packs/kenney-scifi/sounds/forcefield-1.wav +0 -0
- package/packs/kenney-scifi/sounds/forcefield-2.wav +0 -0
- package/packs/kenney-scifi/sounds/impact-1.wav +0 -0
- package/packs/kenney-scifi/sounds/impact-2.wav +0 -0
- package/packs/kenney-scifi/sounds/laser-large.wav +0 -0
- package/packs/kenney-scifi/sounds/laser-retro.wav +0 -0
- package/packs/kenney-scifi/sounds/low-explosion.wav +0 -0
- package/packs/kenney-scifi/sounds/slime.wav +0 -0
- package/packs/kenney-scifi/sounds/thruster-1.wav +0 -0
- package/packs/kenney-scifi/sounds/thruster-2.wav +0 -0
- package/packs/openarena-announcer/sounds/accuracy.wav +0 -0
- package/packs/openarena-announcer/sounds/assist.wav +0 -0
- package/packs/openarena-announcer/sounds/defense.wav +0 -0
- package/packs/openarena-announcer/sounds/denied.wav +0 -0
- package/packs/openarena-announcer/sounds/excellent.wav +0 -0
- package/packs/openarena-announcer/sounds/fight.wav +0 -0
- package/packs/openarena-announcer/sounds/gauntlet.wav +0 -0
- package/packs/openarena-announcer/sounds/humiliation.wav +0 -0
- package/packs/openarena-announcer/sounds/impressive.wav +0 -0
- package/packs/openarena-announcer/sounds/one.wav +0 -0
- package/packs/openarena-announcer/sounds/perfect.wav +0 -0
- package/packs/openarena-announcer/sounds/prepare.wav +0 -0
- package/packs/openarena-announcer/sounds/sudden_death.wav +0 -0
- package/packs/openarena-announcer/sounds/takenlead.wav +0 -0
- package/packs/openarena-announcer/sounds/three.wav +0 -0
- package/packs/openarena-announcer/sounds/two.wav +0 -0
- package/packs/openarena-announcer/sounds/voc_holyshit.wav +0 -0
- package/packs/openarena-announcer/sounds/youwin.wav +0 -0
- package/packs/retro-8bit/sounds/button-1.wav +0 -0
- package/packs/retro-8bit/sounds/button-2.wav +0 -0
- package/packs/retro-8bit/sounds/button-3.wav +0 -0
- package/packs/retro-8bit/sounds/coin-1.wav +0 -0
- package/packs/retro-8bit/sounds/coin-2.wav +0 -0
- package/packs/retro-8bit/sounds/coin-cluster.wav +0 -0
- package/packs/retro-8bit/sounds/coin-double.wav +0 -0
- package/packs/retro-8bit/sounds/damage-1.wav +0 -0
- package/packs/retro-8bit/sounds/error-1.wav +0 -0
- package/packs/retro-8bit/sounds/error-2.wav +0 -0
- package/packs/retro-8bit/sounds/error-3.wav +0 -0
- package/packs/retro-8bit/sounds/fanfare-1.wav +0 -0
- package/packs/retro-8bit/sounds/fanfare-2.wav +0 -0
- package/packs/retro-8bit/sounds/fanfare-3.wav +0 -0
- package/packs/retro-8bit/sounds/negative-1.wav +0 -0
- package/packs/retro-8bit/sounds/negative-2.wav +0 -0
- package/packs/retro-8bit/sounds/powerup-1.wav +0 -0
- package/packs/retro-8bit/sounds/powerup-2.wav +0 -0
- package/packs/warzone2100-command/sounds/construction-completed.wav +0 -0
- package/packs/warzone2100-command/sounds/design-completed.wav +0 -0
- package/packs/warzone2100-command/sounds/enemy-detected.wav +0 -0
- package/packs/warzone2100-command/sounds/incoming-enemy-transport.wav +0 -0
- package/packs/warzone2100-command/sounds/incoming-transmission.wav +0 -0
- package/packs/warzone2100-command/sounds/major-research-completed.wav +0 -0
- package/packs/warzone2100-command/sounds/mission-failed.wav +0 -0
- package/packs/warzone2100-command/sounds/mission-objective.wav +0 -0
- package/packs/warzone2100-command/sounds/mission-successful.wav +0 -0
- package/packs/warzone2100-command/sounds/mission-update.wav +0 -0
- package/packs/warzone2100-command/sounds/new-research-available.wav +0 -0
- package/packs/warzone2100-command/sounds/nexus-laugh1.wav +0 -0
- package/packs/warzone2100-command/sounds/nexus-laugh2.wav +0 -0
- package/packs/warzone2100-command/sounds/power-low.wav +0 -0
- package/packs/warzone2100-command/sounds/production-cancelled.wav +0 -0
- package/packs/warzone2100-command/sounds/production-completed.wav +0 -0
- package/packs/warzone2100-command/sounds/reinforcements-available.wav +0 -0
- package/packs/warzone2100-command/sounds/research-completed.wav +0 -0
- package/packs/warzone2100-command/sounds/retreat-heavy-damage.wav +0 -0
- package/packs/warzone2100-command/sounds/structure-under-attack.wav +0 -0
- package/packs/warzone2100-command/sounds/unit-repaired.wav +0 -0
- package/packs/wesnoth-combat/sounds/axe.wav +0 -0
- package/packs/wesnoth-combat/sounds/bow.wav +0 -0
- package/packs/wesnoth-combat/sounds/crossbow.wav +0 -0
- package/packs/wesnoth-combat/sounds/dwarf-laugh.wav +0 -0
- package/packs/wesnoth-combat/sounds/explosion.wav +0 -0
- package/packs/wesnoth-combat/sounds/fanfare-short.wav +0 -0
- package/packs/wesnoth-combat/sounds/flame-big.wav +0 -0
- package/packs/wesnoth-combat/sounds/gold.wav +0 -0
- package/packs/wesnoth-combat/sounds/gryphon-shriek-1.wav +0 -0
- package/packs/wesnoth-combat/sounds/hatchet.wav +0 -0
- package/packs/wesnoth-combat/sounds/heal.wav +0 -0
- package/packs/wesnoth-combat/sounds/lightning.wav +0 -0
- package/packs/wesnoth-combat/sounds/magic-dark.wav +0 -0
- package/packs/wesnoth-combat/sounds/magic-holy-1.wav +0 -0
- package/packs/wesnoth-combat/sounds/magic-missile-1.wav +0 -0
- package/packs/wesnoth-combat/sounds/open-chest.wav +0 -0
- package/packs/wesnoth-combat/sounds/potion.wav +0 -0
- package/packs/wesnoth-combat/sounds/sword-1.wav +0 -0
- package/packs/wesnoth-combat/sounds/wolf-growl-1.wav +0 -0
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
function showHelp() {
|
|
2
|
+
console.log(`
|
|
3
|
+
Usage: pingthings completions <shell>
|
|
4
|
+
|
|
5
|
+
Generate shell completion script.
|
|
6
|
+
|
|
7
|
+
Arguments:
|
|
8
|
+
shell bash, zsh, or fish
|
|
9
|
+
|
|
10
|
+
Install:
|
|
11
|
+
pingthings completions bash >> ~/.bashrc
|
|
12
|
+
pingthings completions zsh >> ~/.zshrc
|
|
13
|
+
pingthings completions fish > ~/.config/fish/completions/pingthings.fish
|
|
14
|
+
`);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const COMMANDS = [
|
|
18
|
+
'play', 'list', 'select', 'browse', 'search', 'sounds',
|
|
19
|
+
'use', 'preview', 'test-events', 'theme', 'config',
|
|
20
|
+
'init', 'create', 'install', 'uninstall', 'random-pack', 'doctor', 'completions',
|
|
21
|
+
];
|
|
22
|
+
|
|
23
|
+
const THEMES = [
|
|
24
|
+
'retro', 'sci-fi', 'arena', 'fantasy', 'ancient',
|
|
25
|
+
'professional', '8bit', 'space', 'chaos', 'reset',
|
|
26
|
+
];
|
|
27
|
+
|
|
28
|
+
const EVENTS = ['done', 'permission', 'complete', 'error', 'blocked'];
|
|
29
|
+
|
|
30
|
+
function bash() {
|
|
31
|
+
return `# pingthings bash completions
|
|
32
|
+
_pingthings() {
|
|
33
|
+
local cur prev commands
|
|
34
|
+
COMPREPLY=()
|
|
35
|
+
cur="\${COMP_WORDS[COMP_CWORD]}"
|
|
36
|
+
prev="\${COMP_WORDS[COMP_CWORD-1]}"
|
|
37
|
+
commands="${COMMANDS.join(' ')}"
|
|
38
|
+
|
|
39
|
+
case "\${prev}" in
|
|
40
|
+
pingthings)
|
|
41
|
+
COMPREPLY=( $(compgen -W "\${commands}" -- "\${cur}") )
|
|
42
|
+
return 0
|
|
43
|
+
;;
|
|
44
|
+
use|preview|sounds|test-events|uninstall)
|
|
45
|
+
local packs=$(pingthings list 2>/dev/null | grep -oE '\\S+-\\S+' | head -20)
|
|
46
|
+
COMPREPLY=( $(compgen -W "\${packs}" -- "\${cur}") )
|
|
47
|
+
return 0
|
|
48
|
+
;;
|
|
49
|
+
theme)
|
|
50
|
+
COMPREPLY=( $(compgen -W "${THEMES.join(' ')}" -- "\${cur}") )
|
|
51
|
+
return 0
|
|
52
|
+
;;
|
|
53
|
+
--event|-e)
|
|
54
|
+
COMPREPLY=( $(compgen -W "${EVENTS.join(' ')}" -- "\${cur}") )
|
|
55
|
+
return 0
|
|
56
|
+
;;
|
|
57
|
+
browse)
|
|
58
|
+
local cats="military arena fantasy sci-fi fps retro ui transport spooky racing"
|
|
59
|
+
COMPREPLY=( $(compgen -W "\${cats}" -- "\${cur}") )
|
|
60
|
+
return 0
|
|
61
|
+
;;
|
|
62
|
+
completions)
|
|
63
|
+
COMPREPLY=( $(compgen -W "bash zsh fish" -- "\${cur}") )
|
|
64
|
+
return 0
|
|
65
|
+
;;
|
|
66
|
+
esac
|
|
67
|
+
|
|
68
|
+
return 0
|
|
69
|
+
}
|
|
70
|
+
complete -F _pingthings pingthings`;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function zsh() {
|
|
74
|
+
return `# pingthings zsh completions
|
|
75
|
+
_pingthings() {
|
|
76
|
+
local -a commands themes events
|
|
77
|
+
commands=(
|
|
78
|
+
'play:Play a sound from the active pack'
|
|
79
|
+
'list:Show available sound packs'
|
|
80
|
+
'select:Interactive pack selector'
|
|
81
|
+
'browse:Browse packs by category'
|
|
82
|
+
'search:Search packs and sounds'
|
|
83
|
+
'sounds:List individual sounds in a pack'
|
|
84
|
+
'use:Set the active sound pack'
|
|
85
|
+
'preview:Preview a random sound from a pack'
|
|
86
|
+
'test-events:Play all event sounds'
|
|
87
|
+
'theme:Apply a sound theme'
|
|
88
|
+
'config:Show or update configuration'
|
|
89
|
+
'init:Set up Claude Code hooks'
|
|
90
|
+
'create:Create a pack from audio files'
|
|
91
|
+
'install:Install a pack from GitHub or local path'
|
|
92
|
+
'uninstall:Remove a user-installed pack'
|
|
93
|
+
'random-pack:Switch to a random pack'
|
|
94
|
+
'doctor:Diagnose audio setup'
|
|
95
|
+
'completions:Generate shell completions'
|
|
96
|
+
)
|
|
97
|
+
themes=(${THEMES.join(' ')})
|
|
98
|
+
events=(${EVENTS.join(' ')})
|
|
99
|
+
|
|
100
|
+
_arguments '1:command:->cmds' '*::arg:->args'
|
|
101
|
+
|
|
102
|
+
case "$state" in
|
|
103
|
+
cmds)
|
|
104
|
+
_describe -t commands 'pingthings command' commands
|
|
105
|
+
;;
|
|
106
|
+
args)
|
|
107
|
+
case $words[1] in
|
|
108
|
+
use|preview|sounds|test-events|uninstall)
|
|
109
|
+
local packs=($(pingthings list 2>/dev/null | grep -oE '\\S+-\\S+' | head -20))
|
|
110
|
+
_describe -t packs 'pack' packs
|
|
111
|
+
;;
|
|
112
|
+
theme)
|
|
113
|
+
_describe -t themes 'theme' themes
|
|
114
|
+
;;
|
|
115
|
+
browse)
|
|
116
|
+
local cats=(military arena fantasy sci-fi fps retro ui transport spooky racing)
|
|
117
|
+
_describe -t categories 'category' cats
|
|
118
|
+
;;
|
|
119
|
+
completions)
|
|
120
|
+
_describe -t shells 'shell' '(bash zsh fish)'
|
|
121
|
+
;;
|
|
122
|
+
esac
|
|
123
|
+
;;
|
|
124
|
+
esac
|
|
125
|
+
}
|
|
126
|
+
compdef _pingthings pingthings`;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function fish() {
|
|
130
|
+
const lines = [
|
|
131
|
+
'# pingthings fish completions',
|
|
132
|
+
'complete -c pingthings -f',
|
|
133
|
+
];
|
|
134
|
+
|
|
135
|
+
const cmdDescs = {
|
|
136
|
+
play: 'Play a sound', list: 'Show packs', select: 'Interactive picker',
|
|
137
|
+
browse: 'Browse by category', search: 'Search packs', sounds: 'List sounds',
|
|
138
|
+
use: 'Set active pack', preview: 'Preview a pack', 'test-events': 'Test event sounds',
|
|
139
|
+
theme: 'Apply a theme', config: 'Configuration', init: 'Set up hooks',
|
|
140
|
+
create: 'Create a pack', install: 'Install a pack', uninstall: 'Remove a pack',
|
|
141
|
+
'random-pack': 'Random pack', doctor: 'Diagnose setup', completions: 'Shell completions',
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
for (const [cmd, desc] of Object.entries(cmdDescs)) {
|
|
145
|
+
lines.push(`complete -c pingthings -n '__fish_use_subcommand' -a '${cmd}' -d '${desc}'`);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
for (const t of THEMES) {
|
|
149
|
+
lines.push(`complete -c pingthings -n '__fish_seen_subcommand_from theme' -a '${t}'`);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
for (const e of EVENTS) {
|
|
153
|
+
lines.push(`complete -c pingthings -n '__fish_seen_subcommand_from play' -l 'event' -a '${e}'`);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
return lines.join('\n');
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
export default function completions(args) {
|
|
160
|
+
const shell = args[0];
|
|
161
|
+
|
|
162
|
+
if (!shell || shell === '--help' || shell === '-h') {
|
|
163
|
+
showHelp();
|
|
164
|
+
if (!shell) process.exit(1);
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
switch (shell) {
|
|
169
|
+
case 'bash':
|
|
170
|
+
console.log(bash());
|
|
171
|
+
break;
|
|
172
|
+
case 'zsh':
|
|
173
|
+
console.log(zsh());
|
|
174
|
+
break;
|
|
175
|
+
case 'fish':
|
|
176
|
+
console.log(fish());
|
|
177
|
+
break;
|
|
178
|
+
default:
|
|
179
|
+
console.error(`Unknown shell: ${shell}. Use bash, zsh, or fish.`);
|
|
180
|
+
process.exit(1);
|
|
181
|
+
}
|
|
182
|
+
}
|
package/src/cli/config.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { readConfig, writeConfig, VALID_MODES, VALID_EVENTS } from '../config.js';
|
|
2
2
|
|
|
3
|
-
const VALID_KEYS = ['activePack', 'mode', 'specificSound', 'volume', 'eventPacks'];
|
|
3
|
+
const VALID_KEYS = ['activePack', 'mode', 'specificSound', 'volume', 'eventPacks', 'cooldown', 'quietHours', 'notifications'];
|
|
4
4
|
|
|
5
5
|
function showHelp() {
|
|
6
6
|
console.log(`
|
|
@@ -17,13 +17,16 @@ Keys:
|
|
|
17
17
|
mode random, specific, or informational
|
|
18
18
|
specificSound Sound name for specific mode
|
|
19
19
|
volume Playback volume (0-100)
|
|
20
|
+
cooldown Avoid repeating the same sound (true/false)
|
|
21
|
+
quietHours Mute during hours, e.g. "22-7" (10pm-7am)
|
|
20
22
|
eventPacks Per-event pack overrides (use "pingthings config eventPacks.<event> <pack>")
|
|
21
23
|
|
|
22
24
|
Examples:
|
|
23
25
|
pingthings config Show full config
|
|
24
|
-
pingthings config volume Show current volume
|
|
25
26
|
pingthings config volume 50 Set volume to 50%
|
|
26
|
-
pingthings config
|
|
27
|
+
pingthings config cooldown false Disable cooldown
|
|
28
|
+
pingthings config quietHours 22-7 Mute 10pm to 7am
|
|
29
|
+
pingthings config quietHours null Disable quiet hours
|
|
27
30
|
pingthings config eventPacks.error openarena-announcer
|
|
28
31
|
`);
|
|
29
32
|
}
|
|
@@ -109,6 +112,32 @@ export default function config(args) {
|
|
|
109
112
|
return;
|
|
110
113
|
}
|
|
111
114
|
|
|
115
|
+
// Validate boolean keys
|
|
116
|
+
if (key === 'notifications' || key === 'cooldown') {
|
|
117
|
+
if (value !== 'true' && value !== 'false') {
|
|
118
|
+
console.error(`${key} must be true or false.`);
|
|
119
|
+
process.exit(1);
|
|
120
|
+
}
|
|
121
|
+
const cfg = readConfig();
|
|
122
|
+
cfg[key] = value === 'true';
|
|
123
|
+
writeConfig(cfg);
|
|
124
|
+
console.log(`${key} set to: ${cfg[key]}`);
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// Validate quietHours
|
|
129
|
+
if (key === 'quietHours') {
|
|
130
|
+
if (value !== 'null' && !/^\d{1,2}-\d{1,2}$/.test(value)) {
|
|
131
|
+
console.error('Quiet hours must be in format "HH-HH" (e.g., "22-7") or "null" to disable.');
|
|
132
|
+
process.exit(1);
|
|
133
|
+
}
|
|
134
|
+
const cfg = readConfig();
|
|
135
|
+
cfg.quietHours = value === 'null' ? null : value;
|
|
136
|
+
writeConfig(cfg);
|
|
137
|
+
console.log(`quietHours set to: ${cfg.quietHours ?? '(disabled)'}`);
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
|
|
112
141
|
// Two args: set value
|
|
113
142
|
const cfg = readConfig();
|
|
114
143
|
cfg[key] = value === 'null' ? null : value;
|
package/src/cli/create.js
CHANGED
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import { execFileSync } from 'node:child_process';
|
|
2
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import { platform, homedir } from 'node:os';
|
|
5
|
+
import { readConfig, getConfigDir } from '../config.js';
|
|
6
|
+
import { listPacks } from '../packs.js';
|
|
7
|
+
|
|
8
|
+
function showHelp() {
|
|
9
|
+
console.log(`
|
|
10
|
+
Usage: pingthings doctor
|
|
11
|
+
|
|
12
|
+
Diagnose audio setup, check player availability, verify packs,
|
|
13
|
+
and validate Claude Code hook configuration.
|
|
14
|
+
`);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function check(label, fn) {
|
|
18
|
+
try {
|
|
19
|
+
const result = fn();
|
|
20
|
+
if (result === true) {
|
|
21
|
+
console.log(` OK ${label}`);
|
|
22
|
+
} else if (result === false) {
|
|
23
|
+
console.log(` !! ${label}`);
|
|
24
|
+
} else {
|
|
25
|
+
console.log(` OK ${label}: ${result}`);
|
|
26
|
+
}
|
|
27
|
+
return result;
|
|
28
|
+
} catch (err) {
|
|
29
|
+
console.log(` !! ${label}: ${err.message}`);
|
|
30
|
+
return false;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function commandExists(cmd) {
|
|
35
|
+
try {
|
|
36
|
+
execFileSync('which', [cmd], { stdio: 'pipe' });
|
|
37
|
+
return true;
|
|
38
|
+
} catch {
|
|
39
|
+
return false;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export default function doctor(args) {
|
|
44
|
+
if (args.includes('--help') || args.includes('-h')) {
|
|
45
|
+
showHelp();
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
console.log('\npingthings doctor\n');
|
|
50
|
+
|
|
51
|
+
// Platform
|
|
52
|
+
console.log('Platform:');
|
|
53
|
+
check('Operating system', () => {
|
|
54
|
+
const os = platform();
|
|
55
|
+
const names = { darwin: 'macOS', linux: 'Linux', win32: 'Windows' };
|
|
56
|
+
return names[os] || os;
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
// Audio player
|
|
60
|
+
console.log('\nAudio player:');
|
|
61
|
+
let hasPlayer = false;
|
|
62
|
+
if (platform() === 'darwin') {
|
|
63
|
+
hasPlayer = check('afplay available', () => commandExists('afplay'));
|
|
64
|
+
} else if (platform() === 'linux') {
|
|
65
|
+
const pa = check('paplay available (PulseAudio/PipeWire)', () => commandExists('paplay'));
|
|
66
|
+
const al = check('aplay available (ALSA)', () => commandExists('aplay'));
|
|
67
|
+
hasPlayer = pa || al;
|
|
68
|
+
} else if (platform() === 'win32') {
|
|
69
|
+
hasPlayer = check('PowerShell available', () => commandExists('powershell'));
|
|
70
|
+
}
|
|
71
|
+
if (!hasPlayer) {
|
|
72
|
+
console.log('\n No audio player found! Sounds will not play.');
|
|
73
|
+
if (platform() === 'linux') {
|
|
74
|
+
console.log(' Install: sudo apt install pulseaudio-utils (Ubuntu/Debian)');
|
|
75
|
+
console.log(' Or: sudo apt install alsa-utils');
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// Config
|
|
80
|
+
console.log('\nConfiguration:');
|
|
81
|
+
const config = readConfig();
|
|
82
|
+
check('Config directory', () => getConfigDir());
|
|
83
|
+
check('Active pack', () => config.activePack);
|
|
84
|
+
check('Mode', () => config.mode);
|
|
85
|
+
check('Volume', () => `${config.volume}%`);
|
|
86
|
+
if (config.quietHours) {
|
|
87
|
+
check('Quiet hours', () => config.quietHours);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// Packs
|
|
91
|
+
console.log('\nPacks:');
|
|
92
|
+
const packs = listPacks();
|
|
93
|
+
check('Built-in packs', () => {
|
|
94
|
+
const builtIn = packs.filter(p => p.isBuiltIn);
|
|
95
|
+
return `${builtIn.length} packs, ${builtIn.reduce((s, p) => s + p.soundCount, 0)} sounds`;
|
|
96
|
+
});
|
|
97
|
+
check('User packs', () => {
|
|
98
|
+
const user = packs.filter(p => !p.isBuiltIn);
|
|
99
|
+
return user.length > 0 ? `${user.length} packs` : 'none';
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
// Active pack validation
|
|
103
|
+
const activePack = packs.find(p => p.name === config.activePack);
|
|
104
|
+
if (!activePack) {
|
|
105
|
+
check('Active pack exists', () => { throw new Error(`"${config.activePack}" not found`); });
|
|
106
|
+
} else {
|
|
107
|
+
check('Active pack valid', () => `${activePack.name} (${activePack.soundCount} sounds)`);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// Claude Code hooks
|
|
111
|
+
console.log('\nClaude Code integration:');
|
|
112
|
+
const settingsPath = join(homedir(), '.claude', 'settings.json');
|
|
113
|
+
if (existsSync(settingsPath)) {
|
|
114
|
+
try {
|
|
115
|
+
const settings = JSON.parse(readFileSync(settingsPath, 'utf8'));
|
|
116
|
+
const hooks = settings.hooks || {};
|
|
117
|
+
const hasPingthings = JSON.stringify(hooks).includes('pingthings');
|
|
118
|
+
check('settings.json found', () => true);
|
|
119
|
+
check('pingthings hooks configured', () => hasPingthings);
|
|
120
|
+
if (hasPingthings) {
|
|
121
|
+
const hookTypes = Object.keys(hooks).filter(k =>
|
|
122
|
+
JSON.stringify(hooks[k]).includes('pingthings')
|
|
123
|
+
);
|
|
124
|
+
check('Hook events', () => hookTypes.join(', '));
|
|
125
|
+
}
|
|
126
|
+
} catch {
|
|
127
|
+
check('settings.json valid', () => false);
|
|
128
|
+
}
|
|
129
|
+
} else {
|
|
130
|
+
check('settings.json found', () => { throw new Error('Run "pingthings init" to set up'); });
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
console.log('');
|
|
134
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { createInterface } from 'node:readline';
|
|
2
|
+
import { writeConfig, getDefaults } from '../config.js';
|
|
3
|
+
import { listPacks, getPackSounds, pickRandom } from '../packs.js';
|
|
4
|
+
import { playSound } from '../player.js';
|
|
5
|
+
import { basename } from 'node:path';
|
|
6
|
+
|
|
7
|
+
export async function runFirstTimeSetup() {
|
|
8
|
+
const packs = listPacks();
|
|
9
|
+
|
|
10
|
+
console.log('\n ================================================');
|
|
11
|
+
console.log(' WELCOME TO PINGTHINGS!');
|
|
12
|
+
console.log(' Your terminal is about to get a LOT cooler.');
|
|
13
|
+
console.log(' ================================================\n');
|
|
14
|
+
console.log(' Let\'s pick your first sound pack.\n');
|
|
15
|
+
|
|
16
|
+
for (let i = 0; i < packs.length; i++) {
|
|
17
|
+
console.log(` ${i + 1}. ${packs[i].name} (${packs[i].category})`);
|
|
18
|
+
console.log(` ${packs[i].description}`);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
console.log('\n Enter a number to preview, then press enter to confirm.\n');
|
|
22
|
+
|
|
23
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
24
|
+
|
|
25
|
+
const chosen = await new Promise((resolve) => {
|
|
26
|
+
const ask = () => {
|
|
27
|
+
rl.question(' Pick a pack (1-' + packs.length + '): ', (answer) => {
|
|
28
|
+
const num = parseInt(answer.trim(), 10);
|
|
29
|
+
if (isNaN(num) || num < 1 || num > packs.length) {
|
|
30
|
+
console.log(` Enter a number between 1 and ${packs.length}.`);
|
|
31
|
+
ask();
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const pack = packs[num - 1];
|
|
36
|
+
const sounds = getPackSounds(pack.name);
|
|
37
|
+
if (sounds.length > 0) {
|
|
38
|
+
const sample = pickRandom(sounds);
|
|
39
|
+
console.log(`\n Preview: ${basename(sample)}`);
|
|
40
|
+
playSound(sample);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
resolve(pack);
|
|
44
|
+
});
|
|
45
|
+
};
|
|
46
|
+
ask();
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
// Save config
|
|
50
|
+
const config = getDefaults();
|
|
51
|
+
config.activePack = chosen.name;
|
|
52
|
+
writeConfig(config);
|
|
53
|
+
|
|
54
|
+
console.log(`\n Active pack set to: ${chosen.name}`);
|
|
55
|
+
console.log('\n Quick tip: Run "pingthings init" to set up Claude Code hooks.');
|
|
56
|
+
console.log(' Or just run "pingthings play" anytime to hear a sound.\n');
|
|
57
|
+
|
|
58
|
+
rl.close();
|
|
59
|
+
}
|
package/src/cli/init.js
CHANGED
|
@@ -113,13 +113,16 @@ export default async function init(args) {
|
|
|
113
113
|
output: process.stdout,
|
|
114
114
|
});
|
|
115
115
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
116
|
+
await new Promise((resolve) => {
|
|
117
|
+
rl.question('Choose (1 or 2): ', (answer) => {
|
|
118
|
+
const choice = answer.trim();
|
|
119
|
+
if (choice === '2') {
|
|
120
|
+
applyHooks('informational');
|
|
121
|
+
} else {
|
|
122
|
+
applyHooks('basic');
|
|
123
|
+
}
|
|
124
|
+
rl.close();
|
|
125
|
+
resolve();
|
|
126
|
+
});
|
|
124
127
|
});
|
|
125
128
|
}
|
package/src/cli/play.js
CHANGED
|
@@ -1,15 +1,18 @@
|
|
|
1
|
-
import { readConfig, VALID_EVENTS } from '../config.js';
|
|
1
|
+
import { readConfig, VALID_EVENTS, getLastPlayed, setLastPlayed, isQuietHours } from '../config.js';
|
|
2
2
|
import { getPackSounds, getEventSounds, pickRandom, resolvePack } from '../packs.js';
|
|
3
3
|
import { playSound } from '../player.js';
|
|
4
|
+
import { sendNotification } from '../notify.js';
|
|
4
5
|
import { basename } from 'node:path';
|
|
5
6
|
|
|
6
7
|
function parseArgs(args) {
|
|
7
|
-
const result = { sound: null, event: null };
|
|
8
|
+
const result = { sound: null, event: null, notify: false };
|
|
8
9
|
|
|
9
10
|
for (let i = 0; i < args.length; i++) {
|
|
10
11
|
if ((args[i] === '--event' || args[i] === '-e') && args[i + 1]) {
|
|
11
12
|
result.event = args[i + 1];
|
|
12
13
|
i++;
|
|
14
|
+
} else if (args[i] === '--notify' || args[i] === '-n') {
|
|
15
|
+
result.notify = true;
|
|
13
16
|
} else if (args[i] === '--help' || args[i] === '-h') {
|
|
14
17
|
showHelp();
|
|
15
18
|
process.exit(0);
|
|
@@ -133,5 +136,32 @@ export default function play(args) {
|
|
|
133
136
|
process.exit(1);
|
|
134
137
|
}
|
|
135
138
|
|
|
139
|
+
// Quiet hours check
|
|
140
|
+
if (isQuietHours(config)) {
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// Cooldown: avoid playing the same sound twice in a row
|
|
145
|
+
if (config.cooldown && !parsed.sound) {
|
|
146
|
+
const lastPlayed = getLastPlayed();
|
|
147
|
+
if (soundFile === lastPlayed) {
|
|
148
|
+
// Pick a different sound from the same pool
|
|
149
|
+
const pool = parsed.event
|
|
150
|
+
? getEventSounds(config.eventPacks?.[parsed.event] || packName, parsed.event)
|
|
151
|
+
: getPackSounds(packName);
|
|
152
|
+
if (pool.length > 1) {
|
|
153
|
+
const alternatives = pool.filter(s => s !== lastPlayed);
|
|
154
|
+
soundFile = pickRandom(alternatives);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
setLastPlayed(soundFile);
|
|
136
160
|
playSound(soundFile, config.volume);
|
|
161
|
+
|
|
162
|
+
// Desktop notification
|
|
163
|
+
if (parsed.notify || config.notifications) {
|
|
164
|
+
const event = parsed.event || 'notification';
|
|
165
|
+
sendNotification('pingthings', `${event}: ${basename(soundFile)}`);
|
|
166
|
+
}
|
|
137
167
|
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { readConfig, writeConfig } from '../config.js';
|
|
2
|
+
import { listPacks, getPackSounds, pickRandom } from '../packs.js';
|
|
3
|
+
import { playSound } from '../player.js';
|
|
4
|
+
import { basename } from 'node:path';
|
|
5
|
+
|
|
6
|
+
function showHelp() {
|
|
7
|
+
console.log(`
|
|
8
|
+
Usage: pingthings random-pack
|
|
9
|
+
|
|
10
|
+
Switch to a random pack for variety. Plays a preview sound from the new pack.
|
|
11
|
+
`);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export default function randomPack(args) {
|
|
15
|
+
if (args.includes('--help') || args.includes('-h')) {
|
|
16
|
+
showHelp();
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const config = readConfig();
|
|
21
|
+
const packs = listPacks();
|
|
22
|
+
|
|
23
|
+
if (packs.length <= 1) {
|
|
24
|
+
console.log('Only one pack available.');
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// Pick a different pack than the current one
|
|
29
|
+
const others = packs.filter(p => p.name !== config.activePack);
|
|
30
|
+
const chosen = others[Math.floor(Math.random() * others.length)];
|
|
31
|
+
|
|
32
|
+
config.activePack = chosen.name;
|
|
33
|
+
writeConfig(config);
|
|
34
|
+
|
|
35
|
+
const sounds = getPackSounds(chosen.name);
|
|
36
|
+
if (sounds.length > 0) {
|
|
37
|
+
const sample = pickRandom(sounds);
|
|
38
|
+
console.log(`Switched to: ${chosen.name} (${chosen.category})`);
|
|
39
|
+
console.log(`Preview: ${basename(sample)}`);
|
|
40
|
+
playSound(sample, config.volume);
|
|
41
|
+
} else {
|
|
42
|
+
console.log(`Switched to: ${chosen.name}`);
|
|
43
|
+
}
|
|
44
|
+
}
|
package/src/cli/select.js
CHANGED
|
@@ -45,37 +45,41 @@ export default async function select(args) {
|
|
|
45
45
|
output: process.stdout,
|
|
46
46
|
});
|
|
47
47
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
48
|
+
await new Promise((resolve) => {
|
|
49
|
+
const ask = () => {
|
|
50
|
+
rl.question('> ', (answer) => {
|
|
51
|
+
const trimmed = answer.trim().toLowerCase();
|
|
52
|
+
|
|
53
|
+
if (trimmed === 'q' || trimmed === 'quit' || trimmed === '') {
|
|
54
|
+
rl.close();
|
|
55
|
+
resolve();
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const num = parseInt(trimmed, 10);
|
|
60
|
+
if (isNaN(num) || num < 1 || num > packs.length) {
|
|
61
|
+
console.log(`Enter 1-${packs.length} or q to quit.`);
|
|
62
|
+
ask();
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const chosen = packs[num - 1];
|
|
67
|
+
config.activePack = chosen.name;
|
|
68
|
+
writeConfig(config);
|
|
69
|
+
|
|
70
|
+
// Preview a sound from the chosen pack
|
|
71
|
+
const sounds = getPackSounds(chosen.name);
|
|
72
|
+
if (sounds.length > 0) {
|
|
73
|
+
const sample = sounds[Math.floor(Math.random() * sounds.length)];
|
|
74
|
+
playSound(sample, config.volume);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
console.log(`\nActive pack set to: ${chosen.name}`);
|
|
53
78
|
rl.close();
|
|
54
|
-
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
ask();
|
|
61
|
-
return;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
const chosen = packs[num - 1];
|
|
65
|
-
config.activePack = chosen.name;
|
|
66
|
-
writeConfig(config);
|
|
67
|
-
|
|
68
|
-
// Preview a sound from the chosen pack
|
|
69
|
-
const sounds = getPackSounds(chosen.name);
|
|
70
|
-
if (sounds.length > 0) {
|
|
71
|
-
const sample = sounds[Math.floor(Math.random() * sounds.length)];
|
|
72
|
-
playSound(sample, config.volume);
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
console.log(`\nActive pack set to: ${chosen.name}`);
|
|
76
|
-
rl.close();
|
|
77
|
-
});
|
|
78
|
-
};
|
|
79
|
-
|
|
80
|
-
ask();
|
|
79
|
+
resolve();
|
|
80
|
+
});
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
ask();
|
|
84
|
+
});
|
|
81
85
|
}
|
package/src/cli/uninstall.js
CHANGED
|
@@ -25,6 +25,11 @@ export default function uninstall(args) {
|
|
|
25
25
|
return;
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
+
if (packName.includes('..') || packName.includes('/') || packName.includes('\\')) {
|
|
29
|
+
console.error('Invalid pack name.');
|
|
30
|
+
process.exit(1);
|
|
31
|
+
}
|
|
32
|
+
|
|
28
33
|
const userPackDir = join(getConfigDir(), 'packs', packName);
|
|
29
34
|
|
|
30
35
|
if (!existsSync(userPackDir)) {
|