{"_id":"@amenophis1er/claude-voice","_rev":"11-a1bcac8c8da556a428ac138c6dcd7873","name":"@amenophis1er/claude-voice","dist-tags":{"latest":"0.6.4"},"versions":{"0.1.0":{"name":"@amenophis1er/claude-voice","version":"0.1.0","keywords":["claude-code","tts","voice","hooks","plugin"],"license":"MIT","_id":"@amenophis1er/claude-voice@0.1.0","maintainers":[{"name":"amenophis1er","email":"amenophis@amenophis.dev"}],"homepage":"https://github.com/amenophis1er/claude-voice#readme","bugs":{"url":"https://github.com/amenophis1er/claude-voice/issues"},"bin":{"claude-voice":"dist/cli.js"},"dist":{"shasum":"1c024e7fa88de22fce81d0eb59f2a34b1a757cba","tarball":"https://registry.npmjs.org/@amenophis1er/claude-voice/-/claude-voice-0.1.0.tgz","fileCount":21,"integrity":"sha512-fs2osNjbAqaAq16jNm1KdquqSTF7a/tnW4mCXEbuUtSgGP7dfQiCK2YRsQa6LNISP2Ox7NrR1t/b9i6agRibCg==","signatures":[{"sig":"MEQCIASrQBNBtHYUuhpjSqNa8UzTKck5joZ8Ltd9HkVUb8HMAiAj1oTpnAnmy2mchopXT5foGpP4xhe5kb3NuY/F4wbQPw==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":48370},"type":"module","engines":{"node":">=20"},"gitHead":"83b63c5de4f7cb898d2b54543af34967b066d6e6","scripts":{"say":"node src/cli.ts test","init":"node src/cli.ts init","list":"node src/cli.ts list","test":"node test/verify.mjs","build":"tsc -p tsconfig.build.json","check":"npm run typecheck && npm run build && npm run test","config":"node src/cli.ts config","voices":"node src/cli.ts voices","prepack":"npm run build","typecheck":"tsc --noEmit","hooks:install":"node src/cli.ts install","hooks:uninstall":"node src/cli.ts uninstall"},"_npmUser":{"name":"amenophis1er","email":"amenophis@amenophis.dev"},"repository":{"url":"git+https://github.com/amenophis1er/claude-voice.git","type":"git"},"_npmVersion":"11.17.0","description":"Give Claude Code a voice — selective, tasteful spoken summaries and attention cues. Quiet by default.","directories":{},"_nodeVersion":"26.5.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"typescript":"^5.7.0","@types/node":"^22.0.0"},"_npmOperationalInternal":{"tmp":"tmp/claude-voice_0.1.0_1785719887515_0.2012402539682645","host":"s3://npm-registry-packages-npm-production"}},"0.2.0":{"name":"@amenophis1er/claude-voice","version":"0.2.0","keywords":["claude-code","tts","voice","hooks","plugin"],"license":"MIT","_id":"@amenophis1er/claude-voice@0.2.0","maintainers":[{"name":"amenophis1er","email":"amenophis@amenophis.dev"}],"homepage":"https://github.com/amenophis1er/claude-voice#readme","bugs":{"url":"https://github.com/amenophis1er/claude-voice/issues"},"bin":{"claude-voice":"dist/cli.js"},"dist":{"shasum":"4501a050317c84955888c2a8207af2137e1e706e","tarball":"https://registry.npmjs.org/@amenophis1er/claude-voice/-/claude-voice-0.2.0.tgz","fileCount":22,"integrity":"sha512-MFxV1oXcKWmcUrFepw/GLB/0vX0GJv+7kaEFozFEww+Tlid3t/f1E5bX9btNvsNOsLcbU2JVttZnR0dtctWCBw==","signatures":[{"sig":"MEQCIA9rhlrTd3PucQkqwKPQ5BFTDghbu72z9z7egyxnb8nZAiBTfm42qyhRnSDMh4er3NYAHUlEmCK7XVaIuGEZqzqnQw==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@amenophis1er%2fclaude-voice@0.2.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":54196},"type":"module","engines":{"node":">=20"},"gitHead":"7cca09126436f9d81125913144f01a936746bc21","scripts":{"say":"node src/cli.ts test","init":"node src/cli.ts init","list":"node src/cli.ts list","test":"node test/verify.mjs","build":"tsc -p tsconfig.build.json","check":"npm run typecheck && npm run build && npm run test","config":"node src/cli.ts config","voices":"node src/cli.ts voices","prepack":"npm run build","typecheck":"tsc --noEmit","hooks:install":"node src/cli.ts install","hooks:uninstall":"node src/cli.ts uninstall"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:457109fd-7c6f-4ed7-8df5-cfeec5d1f3e1"}},"repository":{"url":"git+https://github.com/amenophis1er/claude-voice.git","type":"git"},"_npmVersion":"11.16.0","description":"Give Claude Code a voice — selective, tasteful spoken summaries and attention cues. Quiet by default.","directories":{},"_nodeVersion":"24.18.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"typescript":"^5.7.0","@types/node":"^22.0.0"},"_npmOperationalInternal":{"tmp":"tmp/claude-voice_0.2.0_1785721101242_0.42643526374969376","host":"s3://npm-registry-packages-npm-production"}},"0.3.0":{"name":"@amenophis1er/claude-voice","version":"0.3.0","keywords":["claude-code","tts","voice","hooks","plugin"],"license":"MIT","_id":"@amenophis1er/claude-voice@0.3.0","maintainers":[{"name":"amenophis1er","email":"amenophis@amenophis.dev"}],"homepage":"https://github.com/amenophis1er/claude-voice#readme","bugs":{"url":"https://github.com/amenophis1er/claude-voice/issues"},"bin":{"claude-voice":"dist/cli.js"},"dist":{"shasum":"f551c26999b9d9cfd7edc75fa38c636fce62b194","tarball":"https://registry.npmjs.org/@amenophis1er/claude-voice/-/claude-voice-0.3.0.tgz","fileCount":23,"integrity":"sha512-OLF/tI56sK+llUcRKKXmN1LGnYqNe50U04MIz3m6uAOb5OsQs83YlVT29aWSdwPuLpEuuDk/rDs5dRiiukrCxA==","signatures":[{"sig":"MEUCIAlI/PQrDbEii/A+VEF8XQ/oMZpbnabngr5uujrkx59bAiEA/phL1u4etVlNnw573d4z2aTkuI52fQ3XyW8TTehXJlQ=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@amenophis1er%2fclaude-voice@0.3.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":57792},"type":"module","engines":{"node":">=20"},"gitHead":"fd91c670fbf5143cb6f1cd121e116c695d57bb8e","scripts":{"say":"node src/cli.ts test","init":"node src/cli.ts init","list":"node src/cli.ts list","test":"node test/verify.mjs","build":"tsc -p tsconfig.build.json","check":"npm run typecheck && npm run build && npm run test","config":"node src/cli.ts config","voices":"node src/cli.ts voices","prepack":"npm run build","typecheck":"tsc --noEmit","hooks:install":"node src/cli.ts install","hooks:uninstall":"node src/cli.ts uninstall"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:457109fd-7c6f-4ed7-8df5-cfeec5d1f3e1"}},"repository":{"url":"git+https://github.com/amenophis1er/claude-voice.git","type":"git"},"_npmVersion":"11.16.0","description":"Give Claude Code a voice — selective, tasteful spoken summaries and attention cues. Quiet by default.","directories":{},"_nodeVersion":"24.18.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"typescript":"^5.7.0","@types/node":"^22.0.0"},"_npmOperationalInternal":{"tmp":"tmp/claude-voice_0.3.0_1785730832140_0.052724997018548825","host":"s3://npm-registry-packages-npm-production"}},"0.4.0":{"name":"@amenophis1er/claude-voice","version":"0.4.0","keywords":["claude-code","tts","voice","hooks","plugin"],"license":"MIT","_id":"@amenophis1er/claude-voice@0.4.0","maintainers":[{"name":"amenophis1er","email":"amenophis@amenophis.dev"}],"homepage":"https://github.com/amenophis1er/claude-voice#readme","bugs":{"url":"https://github.com/amenophis1er/claude-voice/issues"},"bin":{"claude-voice":"dist/cli.js"},"dist":{"shasum":"3a6af4033d710dae98922baefcc51e3a8c96d1f7","tarball":"https://registry.npmjs.org/@amenophis1er/claude-voice/-/claude-voice-0.4.0.tgz","fileCount":24,"integrity":"sha512-l5qf1tUDNTk9XEZqvFyMSPDcUwwhmvCu/vyE8KpHErVJo0nNMgGp8yUG+SET1cvsEp3ejnPTWQgkhViwWIW1kA==","signatures":[{"sig":"MEUCIQCT/jhVqpWSFVZ/Wyd7m7fl3/vbkg2bsXcXUNQr+X+QMAIgZssmEm9uNrKGVRW6PI8RwiHZ9wy/FQwJ9KAdZkMM2iE=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@amenophis1er%2fclaude-voice@0.4.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":67807},"type":"module","engines":{"node":">=20"},"gitHead":"bb47a9ba13250e1c88a29601f48a96beae3a094d","scripts":{"say":"node src/cli.ts test","init":"node src/cli.ts init","list":"node src/cli.ts list","test":"node test/verify.mjs","build":"tsc -p tsconfig.build.json","check":"npm run typecheck && npm run build && npm run test","config":"node src/cli.ts config","voices":"node src/cli.ts voices","prepack":"npm run build","typecheck":"tsc --noEmit","hooks:install":"node src/cli.ts install","hooks:uninstall":"node src/cli.ts uninstall"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:457109fd-7c6f-4ed7-8df5-cfeec5d1f3e1"}},"repository":{"url":"git+https://github.com/amenophis1er/claude-voice.git","type":"git"},"_npmVersion":"11.16.0","description":"Give Claude Code a voice — selective, tasteful spoken summaries and attention cues. Quiet by default.","directories":{},"_nodeVersion":"24.18.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"typescript":"^5.7.0","@types/node":"^22.0.0"},"_npmOperationalInternal":{"tmp":"tmp/claude-voice_0.4.0_1785732117781_0.7605991665873197","host":"s3://npm-registry-packages-npm-production"}},"0.5.0":{"name":"@amenophis1er/claude-voice","version":"0.5.0","keywords":["claude-code","tts","voice","hooks","plugin"],"license":"MIT","_id":"@amenophis1er/claude-voice@0.5.0","maintainers":[{"name":"amenophis1er","email":"amenophis@amenophis.dev"}],"homepage":"https://github.com/amenophis1er/claude-voice#readme","bugs":{"url":"https://github.com/amenophis1er/claude-voice/issues"},"bin":{"claude-voice":"dist/cli.js"},"dist":{"shasum":"14ab69502e3e65b1f05f67fe5ec48107f0c1705b","tarball":"https://registry.npmjs.org/@amenophis1er/claude-voice/-/claude-voice-0.5.0.tgz","fileCount":28,"integrity":"sha512-LdEqbSzr+VPRvfyZvHUlCy9J7M8jQmrsDEqp37rJ+W77bRYf0jYo66eCSHuqzHZvaeIJLgYYZKZcnzLDyKFS6A==","signatures":[{"sig":"MEQCICoi5WTEwqGzUqCkvlQjYIAajzRTIb6uphCyLLB1uTYzAiBYve6NCBI3V9zNGp91RaugXvqqb+Z+HfLHNtDyrlsBpQ==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@amenophis1er%2fclaude-voice@0.5.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":99157},"type":"module","engines":{"node":">=20"},"gitHead":"5d917db563f2b76ac29058b575ee43184e45b592","scripts":{"say":"node src/cli.ts test","init":"node src/cli.ts init","list":"node src/cli.ts list","test":"node test/verify.mjs","build":"tsc -p tsconfig.build.json","check":"npm run typecheck && npm run build && npm run test","config":"node src/cli.ts config","voices":"node src/cli.ts voices","prepack":"npm run build","typecheck":"tsc --noEmit","hooks:install":"node src/cli.ts install","hooks:uninstall":"node src/cli.ts uninstall"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:457109fd-7c6f-4ed7-8df5-cfeec5d1f3e1"}},"repository":{"url":"git+https://github.com/amenophis1er/claude-voice.git","type":"git"},"_npmVersion":"11.16.0","description":"Give Claude Code a voice — selective, tasteful spoken summaries and attention cues. Quiet by default.","directories":{},"_nodeVersion":"24.18.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"typescript":"^5.7.0","@types/node":"^22.0.0"},"_npmOperationalInternal":{"tmp":"tmp/claude-voice_0.5.0_1785804391522_0.09420460985325985","host":"s3://npm-registry-packages-npm-production"}},"0.5.1":{"name":"@amenophis1er/claude-voice","version":"0.5.1","keywords":["claude-code","tts","voice","hooks","plugin"],"license":"MIT","_id":"@amenophis1er/claude-voice@0.5.1","maintainers":[{"name":"amenophis1er","email":"amenophis@amenophis.dev"}],"homepage":"https://github.com/amenophis1er/claude-voice#readme","bugs":{"url":"https://github.com/amenophis1er/claude-voice/issues"},"bin":{"claude-voice":"dist/cli.js"},"dist":{"shasum":"0fcbe904c244822b0b8f9df48b20b98e77b23f1b","tarball":"https://registry.npmjs.org/@amenophis1er/claude-voice/-/claude-voice-0.5.1.tgz","fileCount":32,"integrity":"sha512-Ktbi39BQk6lkn75/5avC39iEyZUWsIatA77tAv5CszXJPNuT4C02Rl0l19hgO0pLfdIZzhrfIYf/sXo45WISYw==","signatures":[{"sig":"MEUCIA0VEzWUSiNqXdQA3bgd2IcRHrf4CMlW0sXm0hB5j3UCAiEAr+hPMOLCtAv+nb5kQHSXWmcgRq0uHE/NXYmqDb9SHJc=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@amenophis1er%2fclaude-voice@0.5.1","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":150692},"type":"module","engines":{"node":">=20"},"gitHead":"2770551a824a3fee460cb3a5923b52c38c5227af","scripts":{"say":"node src/cli.ts test","init":"node src/cli.ts init","list":"node src/cli.ts list","test":"node test/verify.mjs","build":"tsc -p tsconfig.build.json","check":"npm run typecheck && npm run build && npm run test","config":"node src/cli.ts config","voices":"node src/cli.ts voices","prepack":"npm run build","typecheck":"tsc --noEmit","hooks:install":"node src/cli.ts install","hooks:uninstall":"node src/cli.ts uninstall"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:457109fd-7c6f-4ed7-8df5-cfeec5d1f3e1"}},"repository":{"url":"git+https://github.com/amenophis1er/claude-voice.git","type":"git"},"_npmVersion":"11.16.0","description":"Give Claude Code a voice — selective, tasteful spoken summaries and attention cues. Quiet by default.","directories":{},"_nodeVersion":"24.18.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"typescript":"^5.7.0","@types/node":"^22.0.0"},"_npmOperationalInternal":{"tmp":"tmp/claude-voice_0.5.1_1786461712280_0.19868845980226157","host":"s3://npm-registry-packages-npm-production"}},"0.6.0":{"name":"@amenophis1er/claude-voice","version":"0.6.0","keywords":["claude-code","tts","voice","hooks","plugin"],"license":"MIT","_id":"@amenophis1er/claude-voice@0.6.0","maintainers":[{"name":"amenophis1er","email":"amenophis@amenophis.dev"}],"homepage":"https://github.com/amenophis1er/claude-voice#readme","bugs":{"url":"https://github.com/amenophis1er/claude-voice/issues"},"bin":{"claude-voice":"dist/cli.js"},"dist":{"shasum":"947aeba9416ec9f649e31b452b7c79a5c22f52f7","tarball":"https://registry.npmjs.org/@amenophis1er/claude-voice/-/claude-voice-0.6.0.tgz","fileCount":33,"integrity":"sha512-N8Haa/XW6/jmqs+YZT9y6nK5WD/AH7hk/VHTKOFmYLx5QQnWN2X0+4RhjIUjdWWwj2x1JfjxosguAo/XPxsZFQ==","signatures":[{"sig":"MEUCIQCs6ypjmy/HsOreFzp7juyLSq60l9WmXwREHijDXZy+5gIgBWSx4AQSB8+lcY1KXAUlf1Lis5Wk26zWWv0vllpU0VY=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@amenophis1er%2fclaude-voice@0.6.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":161375},"type":"module","engines":{"node":">=20"},"gitHead":"3d3ea4c057e6fde07f23df3ff3267932fdfd33f7","scripts":{"say":"node src/cli.ts test","init":"node src/cli.ts init","list":"node src/cli.ts list","test":"node test/verify.mjs","build":"tsc -p tsconfig.build.json","check":"npm run typecheck && npm run build && npm run test","config":"node src/cli.ts config","voices":"node src/cli.ts voices","prepack":"npm run build","typecheck":"tsc --noEmit","hooks:install":"node src/cli.ts install","hooks:uninstall":"node src/cli.ts uninstall"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:457109fd-7c6f-4ed7-8df5-cfeec5d1f3e1"}},"repository":{"url":"git+https://github.com/amenophis1er/claude-voice.git","type":"git"},"_npmVersion":"11.16.0","description":"Give Claude Code a voice — selective, tasteful spoken summaries and attention cues. Quiet by default.","directories":{},"_nodeVersion":"24.18.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"typescript":"^5.7.0","@types/node":"^22.0.0"},"_npmOperationalInternal":{"tmp":"tmp/claude-voice_0.6.0_1786473854986_0.8393009869252337","host":"s3://npm-registry-packages-npm-production"}},"0.6.1":{"name":"@amenophis1er/claude-voice","version":"0.6.1","keywords":["claude-code","tts","voice","hooks","plugin"],"license":"MIT","_id":"@amenophis1er/claude-voice@0.6.1","maintainers":[{"name":"amenophis1er","email":"amenophis@amenophis.dev"}],"homepage":"https://github.com/amenophis1er/claude-voice#readme","bugs":{"url":"https://github.com/amenophis1er/claude-voice/issues"},"bin":{"claude-voice":"dist/cli.js"},"dist":{"shasum":"01196cfe8a922e5d6eb44502c27907d29b7d1f9d","tarball":"https://registry.npmjs.org/@amenophis1er/claude-voice/-/claude-voice-0.6.1.tgz","fileCount":33,"integrity":"sha512-AmhCADoiRbBNa5sboYNBbCPt9hXKsb/HPQUrCr4llsSYO8SsYkYS3JNSLTADKBKk/DvQWfYAOvxlpt4Kj3GDuA==","signatures":[{"sig":"MEUCIQDYg7cHidAoVTErm1I9qOCg3lyP/2BsBDxL3WmQ1Z7X8wIgYvn3J108uWlEKJlNLuuBNEVxr7Mm7EjN8nkjTDjeHVY=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@amenophis1er%2fclaude-voice@0.6.1","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":163148},"type":"module","engines":{"node":">=20"},"gitHead":"9a63fdaaefbc3ffea8a8d9ade78902bc24b5ac75","scripts":{"say":"node src/cli.ts test","init":"node src/cli.ts init","list":"node src/cli.ts list","test":"node test/verify.mjs","build":"tsc -p tsconfig.build.json","check":"npm run typecheck && npm run build && npm run test","config":"node src/cli.ts config","voices":"node src/cli.ts voices","prepack":"npm run build","typecheck":"tsc --noEmit","hooks:install":"node src/cli.ts install","hooks:uninstall":"node src/cli.ts uninstall"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:457109fd-7c6f-4ed7-8df5-cfeec5d1f3e1"}},"repository":{"url":"git+https://github.com/amenophis1er/claude-voice.git","type":"git"},"_npmVersion":"11.16.0","description":"Give Claude Code a voice — selective, tasteful spoken summaries and attention cues. Quiet by default.","directories":{},"_nodeVersion":"24.18.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"typescript":"^5.7.0","@types/node":"^22.0.0"},"_npmOperationalInternal":{"tmp":"tmp/claude-voice_0.6.1_1786486522659_0.8436371905029099","host":"s3://npm-registry-packages-npm-production"}},"0.6.2":{"name":"@amenophis1er/claude-voice","version":"0.6.2","keywords":["claude-code","tts","voice","hooks","plugin"],"license":"MIT","_id":"@amenophis1er/claude-voice@0.6.2","maintainers":[{"name":"amenophis1er","email":"amenophis@amenophis.dev"}],"homepage":"https://github.com/amenophis1er/claude-voice#readme","bugs":{"url":"https://github.com/amenophis1er/claude-voice/issues"},"bin":{"claude-voice":"dist/cli.js"},"dist":{"shasum":"58f156763795ff02d0e947ac8414daa3ec439272","tarball":"https://registry.npmjs.org/@amenophis1er/claude-voice/-/claude-voice-0.6.2.tgz","fileCount":33,"integrity":"sha512-AW4RIHhrRm4anB3QouZHF+gomPUM71dnTnDheIoTSgfA6ptveuCpSZy/hAnZK2a8fxz1kNmpfgBTTuZfhaDwuw==","signatures":[{"sig":"MEQCIG6/u/KZ3OWsRJBFZRSThKLCfSwxxVPoUr9efLikK8yjAiAiAMWQuA2xSJLW/dzjy+fQtRFSthhWAbxULi9Sw7evUg==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@amenophis1er%2fclaude-voice@0.6.2","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":164133},"type":"module","engines":{"node":">=20"},"gitHead":"94b206783565f5bb05969da3b8091fcb2ce79a3a","scripts":{"say":"node src/cli.ts test","init":"node src/cli.ts init","list":"node src/cli.ts list","test":"node test/verify.mjs","build":"tsc -p tsconfig.build.json","check":"npm run typecheck && npm run build && npm run test","config":"node src/cli.ts config","voices":"node src/cli.ts voices","prepack":"npm run build","typecheck":"tsc --noEmit","hooks:install":"node src/cli.ts install","hooks:uninstall":"node src/cli.ts uninstall"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:457109fd-7c6f-4ed7-8df5-cfeec5d1f3e1"}},"repository":{"url":"git+https://github.com/amenophis1er/claude-voice.git","type":"git"},"_npmVersion":"11.16.0","description":"Give Claude Code a voice — selective, tasteful spoken summaries and attention cues. Quiet by default.","directories":{},"_nodeVersion":"24.18.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"typescript":"^5.7.0","@types/node":"^22.0.0"},"_npmOperationalInternal":{"tmp":"tmp/claude-voice_0.6.2_1786487622414_0.18179200788716932","host":"s3://npm-registry-packages-npm-production"}},"0.6.3":{"name":"@amenophis1er/claude-voice","version":"0.6.3","keywords":["claude-code","tts","voice","hooks","plugin"],"license":"MIT","_id":"@amenophis1er/claude-voice@0.6.3","maintainers":[{"name":"amenophis1er","email":"amenophis@amenophis.dev"}],"homepage":"https://github.com/amenophis1er/claude-voice#readme","bugs":{"url":"https://github.com/amenophis1er/claude-voice/issues"},"bin":{"claude-voice":"dist/cli.js"},"dist":{"shasum":"93e77ff10a99f6980aa2c8eabec1b12114a1b0bd","tarball":"https://registry.npmjs.org/@amenophis1er/claude-voice/-/claude-voice-0.6.3.tgz","fileCount":33,"integrity":"sha512-gmqZxXBwWUV6MF40zvIwOZTpKT2KG6ZmU5+7xO6GdI8UnGkGb3aZKhttLemBnXGUduV6l+IiNRWgRjt5+hqxvg==","signatures":[{"sig":"MEUCIQDS4Wwf3sN8HSwgRV2/3ki9mx++fsiSoNv31WGXabY7tAIgaXRvRXfSK6DU/id0KAhz5USNjw0Q48rGPAkA3yPOs2U=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@amenophis1er%2fclaude-voice@0.6.3","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":165070},"type":"module","engines":{"node":">=20"},"gitHead":"5674dc0a8874df3d1e0c85465d6017ff56ed1495","scripts":{"say":"node src/cli.ts test","init":"node src/cli.ts init","list":"node src/cli.ts list","test":"node test/verify.mjs","build":"tsc -p tsconfig.build.json","check":"npm run typecheck && npm run build && npm run test","config":"node src/cli.ts config","voices":"node src/cli.ts voices","prepack":"npm run build","typecheck":"tsc --noEmit","hooks:install":"node src/cli.ts install","hooks:uninstall":"node src/cli.ts uninstall"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:457109fd-7c6f-4ed7-8df5-cfeec5d1f3e1"}},"repository":{"url":"git+https://github.com/amenophis1er/claude-voice.git","type":"git"},"_npmVersion":"11.16.0","description":"Give Claude Code a voice — selective, tasteful spoken summaries and attention cues. Quiet by default.","directories":{},"_nodeVersion":"24.18.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"typescript":"^5.7.0","@types/node":"^22.0.0"},"_npmOperationalInternal":{"tmp":"tmp/claude-voice_0.6.3_1786493550176_0.37673875691920977","host":"s3://npm-registry-packages-npm-production"}},"0.6.4":{"_id":"@amenophis1er/claude-voice@0.6.4","bin":{"claude-voice":"dist/cli.js"},"bugs":{"url":"https://github.com/amenophis1er/claude-voice/issues"},"dist":{"shasum":"8f09b43fc398965b660ed736fd12add35b5762dc","tarball":"https://registry.npmjs.org/@amenophis1er/claude-voice/-/claude-voice-0.6.4.tgz","fileCount":33,"integrity":"sha512-zVEln8ky7nrUn/TK1DJsd0J26w4QWolds1/Y0uM5699jkBxgdzHwhG0bkB7pbsr3BbbJm9qI2DSAwyMe0yAS9g==","signatures":[{"sig":"MEUCIQCfPV5Ceo6cLrSRYYO75YajSieN9gLXIdQaxbuRja3x3wIgBUTDZZdxa2G53OoCEoZsVlmHJT0rqIXGxzXfs6TA2zo=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIDeIoaLswaFlhh5eze3ln9MxssLLNx0TBn42ZErDzJerAiEAoOwlGndOwaRNa0dzkqX3RqYoN8X3DRQLhSBky/TaXq0="}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@amenophis1er%2fclaude-voice@0.6.4","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":170333},"name":"@amenophis1er/claude-voice","type":"module","engines":{"node":">=20"},"gitHead":"6c38216f1d9ee49db64735169a9f6db52c90bd4d","license":"MIT","scripts":{"say":"node src/cli.ts test","init":"node src/cli.ts init","list":"node src/cli.ts list","test":"node test/verify.mjs","build":"tsc -p tsconfig.build.json","check":"npm run typecheck && npm run build && npm run test","config":"node src/cli.ts config","voices":"node src/cli.ts voices","prepack":"npm run build","typecheck":"tsc --noEmit","hooks:install":"node src/cli.ts install","hooks:uninstall":"node src/cli.ts uninstall"},"version":"0.6.4","_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:457109fd-7c6f-4ed7-8df5-cfeec5d1f3e1"}},"homepage":"https://github.com/amenophis1er/claude-voice#readme","keywords":["claude-code","tts","voice","hooks","plugin"],"repository":{"url":"git+https://github.com/amenophis1er/claude-voice.git","type":"git"},"_npmVersion":"11.17.0","description":"Give Claude Code a voice — selective, tasteful spoken summaries and attention cues. Quiet by default.","directories":{},"maintainers":[{"name":"amenophis1er","email":"amenophis@amenophis.dev"}],"_nodeVersion":"24.19.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"typescript":"^5.7.0","@types/node":"^22.0.0"},"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/claude-voice_0.6.4_1788047116169_0.5166383788080766"}}},"time":{"created":"2026-08-03T01:18:07.375Z","modified":"2026-08-29T23:45:16.662Z","0.1.0":"2026-08-03T01:18:07.652Z","0.2.0":"2026-08-03T01:38:21.383Z","0.3.0":"2026-08-03T04:20:32.261Z","0.4.0":"2026-08-03T04:41:57.926Z","0.5.0":"2026-08-04T00:46:31.667Z","0.5.1":"2026-08-11T15:21:52.435Z","0.6.0":"2026-08-11T18:44:15.176Z","0.6.1":"2026-08-11T22:15:22.794Z","0.6.2":"2026-08-11T22:33:42.566Z","0.6.3":"2026-08-12T00:12:30.327Z","0.6.4":"2026-08-29T23:45:16.280Z"},"bugs":{"url":"https://github.com/amenophis1er/claude-voice/issues"},"license":"MIT","homepage":"https://github.com/amenophis1er/claude-voice#readme","keywords":["claude-code","tts","voice","hooks","plugin"],"repository":{"url":"git+https://github.com/amenophis1er/claude-voice.git","type":"git"},"description":"Give Claude Code a voice — selective, tasteful spoken summaries and attention cues. Quiet by default.","maintainers":[{"name":"amenophis1er","email":"amenophis@amenophis.dev"}],"readme":"# claude-voice\n\nGive Claude Code a voice — **selective and tasteful, quiet by default.**\n\nIt speaks a one-sentence summary when a *substantial* task finishes, chimes when\nClaude needs you, and otherwise stays silent. No \"read every response aloud\"\nfirehose: the point is to let you look away from the terminal, not to narrate it.\n\nExisting voice plugins either just play a sound, or read *everything* Claude\nsays (overwhelming). claude-voice is built around one idea: **say something only\nwhen it's worth interrupting you.**\n\n## Install\n\n### Option 1 — npx (recommended)\n\n```bash\nnpx @amenophis1er/claude-voice init\n```\n\nThe interactive setup lets you pick a verbosity preset, a voice, and a TTS\nprovider, then wires the hooks into `~/.claude/settings.json`. **Restart Claude\nCode** afterwards and you're done.\n\nBehind the scenes, `init` copies a small compiled runtime (~50 kB, zero\ndependencies) to `~/.claude/voice/app/` and points the hooks at that stable\npath — hooks never touch npx, the network, or your npm cache, and keep working\nwhen you switch Node versions.\n\n- **Upgrade:** `npx @amenophis1er/claude-voice@latest init`\n- **Remove:** `npx @amenophis1er/claude-voice uninstall` (your config is kept)\n\n### Option 2 — Claude Code plugin\n\nInside Claude Code:\n\n```\n/plugin marketplace add amenophis1er/claude-voice\n/plugin install claude-voice@claude-voice\n```\n\nClaude Code manages the hooks itself and updates the plugin with the repo.\nUse *either* the npx install *or* the plugin — not both, or you'll get double\naudio.\n\n### Requirements\n\n- **Node ≥ 20** on your PATH (hooks run small compiled JS files)\n- **Playback:** macOS works out of the box (`say` + `afplay`). Linux needs\n  `espeak-ng` and `paplay` (or `aplay`, tried automatically). Windows uses\n  built-in PowerShell speech. Chimes are macOS-only for now. Cloud providers\n  request WAV on Windows so their audio plays there too.\n\n## What you'll hear\n\nOne knob controls everything — the `preset`:\n\n| preset | needs-you notification | task end | mid-task |\n| --- | --- | --- | --- |\n| `silent` | — | — | — |\n| `chimes` | chime | chime | — |\n| **`summary`** (default) | chime + spoken | spoken summary, *substantial tasks only* | — |\n| `verbose` | chime + spoken | spoken summary, always | spoken milestones |\n\n\"Substantial\" means the task crossed a threshold (default: 3 tool calls or 15\nseconds). Quick back-and-forth stays silent — that's the tasteful part.\n\n**Milestones** (`verbose` only): during a long task, Claude's short progress\nremarks (\"Now turning both old copies into pointer stubs.\") are spoken so you\ncan follow along from across the room — only once the task is already\nsubstantial, at most one per minute, never repeating itself, and never talking\nover other audio. Milestones are also *perishable*: a remark older than two\nintervals is never spoken (during long agent runs the last remark can sit\nunchanged for minutes), and if the speaker is busy a milestone is dropped, not\nqueued — a delayed glance is a wrong glance. The task-end summary always wins:\nit cuts a still-playing milestone.\n\nThe summary you hear isn't a robotic read-back: Claude is taught (via a session\ninstruction the hooks inject) to end real tasks with one natural, speakable\nclosing sentence — no code, paths, or URLs — and that's what gets spoken.\n\n## Voices and providers\n\nThe default (`system`) uses your OS's built-in text-to-speech: zero config, no\nAPI keys, works offline. Three opt-in upgrades:\n\n| provider | quality | needs |\n| --- | --- | --- |\n| `system` (default) | fine | nothing |\n| `kokoro` | great | one-time local install (~350 MB) — free, offline |\n| `elevenlabs` | best | `ELEVENLABS_API_KEY` in your environment |\n| `openai` | great | `OPENAI_API_KEY` in your environment |\n\n### Kokoro — neural voices, fully local\n\nKokoro is a small open-weights TTS model that runs on your CPU (no GPU\nneeded) faster than real time — neural-voice quality with no API key, no\nnetwork, no per-word cost:\n\n```bash\nnpx @amenophis1er/claude-voice kokoro install    # venv + model under ~/.claude/voice/kokoro\nnpx @amenophis1er/claude-voice kokoro voice      # re-pick the voice — each speaks as you browse\nnpx @amenophis1er/claude-voice kokoro status     # install state, disk use, server state\nnpx @amenophis1er/claude-voice kokoro uninstall  # removes everything it installed\n```\n\nThe install is self-contained under `~/.claude/voice/kokoro` (a private\nPython venv plus the model — nothing global, no Homebrew packages), ends with\na spoken smoke test, and finishes with a voice picker where each voice\nintroduces itself as you arrow onto it. It needs Python 3.10–3.13 on your\nPATH, or [`uv`](https://docs.astral.sh/uv/) (preferred — it fetches its own).\n\nSynthesis runs through a tiny localhost server that starts on demand, is\npre-warmed when you submit a prompt, and exits by itself after 10 idle\nminutes. Warm latency is a few hundred milliseconds (`npx @amenophis1er/claude-voice stats`\nshows it as `synthesis kokoro`). Uninstalling deletes that one directory and\npoints config back at the system voice — nothing else to clean up.\n\n**Bring your own TTS:** the `openai` provider works with any OpenAI-compatible\nendpoint (LocalAI, a self-hosted server) — set `options.baseUrl` and\nyour key, and pick a voice your server knows:\n\n```json\n{\n  \"provider\": \"openai\",\n  \"voice\": \"af_bella\",\n  \"options\": { \"baseUrl\": \"https://tts.example.com/v1\", \"apiKeyCommand\": \"…\" }\n}\n```\n\nWith a custom `baseUrl`, `model` is only sent if you set `options.model` —\nyour server's default is usually right.\n\nIf a provider fails (no key, kokoro not installed, network down, timeout), it\nfalls back to the system voice automatically — you still hear your summary.\n\n**Keys from a secret manager:** hooks run outside your shell rc, so env vars\nset by on-demand loaders are often absent. Instead of exporting keys globally,\ngive the provider a command that prints the key:\n\n```json\n{\n  \"provider\": \"elevenlabs\",\n  \"options\": { \"apiKeyCommand\": \"op read op://dev-env/ELEVENLABS_API_KEY/credential\" }\n}\n```\n\nResolution order: env var → `options.api_key` (plaintext, discouraged) →\n`options.apiKeyCommand` (1Password `op`, macOS `security`, `pass`, …).\n\nUseful commands:\n\n```bash\nnpx @amenophis1er/claude-voice voices          # list system voices (try \"Ava (Premium)\" on macOS)\nnpx @amenophis1er/claude-voice test \"Hello\"    # hear the current voice right now\nnpx @amenophis1er/claude-voice list            # list providers\nnpx @amenophis1er/claude-voice config          # show active config + where it lives\nnpx @amenophis1er/claude-voice recap           # speak where the latest session stands\nnpx @amenophis1er/claude-voice stats           # audio latency + outcome metrics (24h; try `7d`, `--json`)\n```\n\n`stats` shows where the time goes between a hook firing and audio being\naudible — dispatch overhead, TTS synthesis (per provider), speaker-queue\nwait — plus outcomes: played, dropped (speaker busy), and upstream skips\n(throttled, muted, quiet hours). Metrics are always on and cost nothing; the\nJSONL file rotates at ~512 KB.\n\n## On-demand recap (hotkey)\n\n`claude-voice recap` finds your most recently active Claude Code session and\nspeaks where it stands — Claude Code's own idle recap when that's the newest\nword, otherwise the closing sentence of the last assistant message — prefixed\nwith the project name. It speaks even while muted (you asked), which makes it\nperfect on a global hotkey: glance away from the screen, tap the key, hear the\nstate of play.\n\nClaude Code's in-app keybindings can't run commands (and terminals can't even\nsee a bare modifier tap), so bind it at the OS level.\n\n**macOS, zero extra installs** — generate a ready-made Shortcut:\n\n```bash\nnpx @amenophis1er/claude-voice shortcut\n```\n\nThis builds the Shortcuts workflow with your machine's real paths, signs it\nlocally (macOS refuses unsigned shortcut files), and opens the import dialog.\nClick *Add Shortcut*, then in the shortcut's ⓘ details panel assign a global\nhotkey — ⌃⌥V is a safe, mnemonic choice (avoid ⌃⌥R: Claude Code uses it for\nprompt search). The hotkey itself can't ship in the file; Apple stores those\nper device.\n\nThe natural companion — especially with `\"speech\": \"full\"` — is a hotkey that\n**shuts the voice up mid-word**:\n\n```bash\nnpx @amenophis1er/claude-voice shortcut stop   # generate \"Claude voice stop\"\nnpx @amenophis1er/claude-voice stop            # same thing from a terminal\n```\n\n`stop` cuts whatever is playing right now, across all sessions, and says\nnothing about the future (unlike `mute`). Typing a new prompt still interrupts\nautomatically, as always.\n\n**Prefer a double-tap gesture?** Double-tap **Right Ctrl** with\n[Karabiner-Elements](https://karabiner-elements.pqrs.org) (macOS):\n\n```json\n{\n  \"description\": \"Double-tap Right Ctrl → speak Claude session recap\",\n  \"manipulators\": [\n    {\n      \"type\": \"basic\",\n      \"from\": { \"key_code\": \"right_control\", \"modifiers\": { \"optional\": [\"any\"] } },\n      \"conditions\": [{ \"type\": \"variable_if\", \"name\": \"rctrl_tap\", \"value\": 1 }],\n      \"to\": [{ \"shell_command\": \"/opt/homebrew/bin/node $HOME/.claude/voice/app/cli.js recap\" }]\n    },\n    {\n      \"type\": \"basic\",\n      \"from\": { \"key_code\": \"right_control\", \"modifiers\": { \"optional\": [\"any\"] } },\n      \"to\": [\n        { \"key_code\": \"right_control\" },\n        { \"set_variable\": { \"name\": \"rctrl_tap\", \"value\": 1 } }\n      ],\n      \"to_delayed_action\": {\n        \"to_if_invoked\": [{ \"set_variable\": { \"name\": \"rctrl_tap\", \"value\": 0 } }],\n        \"to_if_canceled\": [{ \"set_variable\": { \"name\": \"rctrl_tap\", \"value\": 0 } }]\n      }\n    }\n  ]\n}\n```\n\nAdjust the `shell_command` for your setup: Karabiner runs with a minimal\n`PATH`, so use an absolute `node` path (`which node`), and point at\n`~/.claude/voice/app/cli.js` (npx install) or `<your clone>/src/cli.ts`\n(source install). Raycast, Hammerspoon, or skhd work just as well with a\nnormal key combo.\n\n## Configuration\n\n`~/.claude/voice/config.json` — everything is optional; shown with defaults:\n\n```json\n{\n  \"preset\": \"summary\",\n  \"speech\": \"closing\",\n  \"provider\": \"system\",\n  \"voice\": null,\n  \"rate\": 1,\n  \"options\": {},\n  \"throttleSeconds\": 20,\n  \"milestoneIntervalSeconds\": 60,\n  \"substantial\": { \"minToolCalls\": 3, \"minDurationSeconds\": 15 },\n  \"speakOnlyWhenUnfocused\": false,\n  \"announceProject\": \"auto\",\n  \"quietHours\": { \"start\": 22, \"end\": 8 }\n}\n```\n\n| field | meaning |\n| --- | --- |\n| `preset` | The one knob — see table above. It decides **when** to speak. |\n| `speech` | How much of a spoken reply is read: `\"closing\"` (the closing sentence — default) or `\"full\"` (the entire reply, sanitized: code, paths, and URLs stripped). Full pairs best with `kokoro` — free, starts in ~0.5 s, and a new prompt cuts it off instantly. |\n| `provider` | `system`, `kokoro`, `elevenlabs`, or `openai`. |\n| `voice` | Provider-specific voice name/id. |\n| `rate` | Speech speed, `1` = normal. |\n| `options` | Free-form provider extras, e.g. `{ \"model_id\": \"eleven_turbo_v2_5\" }`. |\n| `throttleSeconds` | Minimum gap between two spoken summaries in one session. |\n| `milestoneIntervalSeconds` | Minimum gap between two spoken milestones (`verbose`). |\n| `substantial` | A task must clear **one** threshold to be summarized. |\n| `speakOnlyWhenUnfocused` | Speak only when your terminal is **not** the frontmost app (macOS). |\n| `announceProject` | Prefix audio with the project folder name (\"claude voice: Task complete.\"). `\"auto\"` = only while other sessions are active; `\"always\"`; `\"off\"`. On macOS, `\"auto\"` also skips the prefix when you're looking straight at *this* session's own tab (Terminal.app or iTerm2) — there's nothing to disambiguate. |\n| `quietHours` | 24h local time; wraps midnight (`22 → 8` means 10pm–8am). |\n\nEdit the file directly or rerun `npx @amenophis1er/claude-voice init` — changes apply on the\nnext task, no restart needed.\n\n## Muting on purpose\n\nSometimes you want silence *now* — a call, a screen share, pairing. Three ways,\nall equivalent:\n\n```\n/claude-voice mute 1h    # inside Claude Code (slash command, installed with the hooks)\n/claude-voice unmute\n/claude-voice status\n```\n\n(Why not `/voice`? That name is a Claude Code built-in.)\n\n```bash\nnpx @amenophis1er/claude-voice mute 2h    # or: mute 30m, mute 1d, mute (= until unmute)\nnpx @amenophis1er/claude-voice unmute\n```\n\nA mute is **global** (all sessions — mute means the room goes quiet), survives\nrestarts, and expires on its own when given a duration. This is separate from\nthe *automatic* silencers: `quietHours` (config) and `speakOnlyWhenUnfocused`\n(speak only when the terminal isn't the frontmost app).\n\n## Nice to know\n\n- **Parallel sessions don't fight:** state is per-session, so two Claude Code\n  windows won't interrupt or throttle each other.\n- **You can tell sessions apart:** while more than one session is running,\n  spoken audio is prefixed with the project folder name — \"claude voice: Task\n  complete.\" — so you know which window is talking (`announceProject`).\n  On macOS with Terminal.app or iTerm2, the prefix is also skipped when you're\n  looking at that session's own tab: the name adds nothing when the session is\n  right in front of you. Detection needs the Automation permission (asked the\n  first time) and fails open — when in doubt, the prefix stays. tmux, ssh, and\n  non-scriptable terminals keep the prefix as before.\n- **It shuts up when you type:** submitting a new prompt instantly kills any\n  audio still playing.\n- **It never stalls Claude:** hooks are async and audio plays in a detached\n  worker process.\n- **One voice at a time:** playback is serialized machine-wide — a milestone,\n  a notification, and another session's summary queue up instead of talking\n  over each other. (Synthesis still runs in parallel; only the speaker is\n  exclusive.)\n- **Notification cues are tailored:** permission prompt, idle, needs-input, and\n  task-complete each get an appropriate phrase.\n- **No stale \"Claude is waiting for you\":** the idle nudge is skipped for 10\n  minutes after a spoken summary — you already heard the job is done. A\n  *silent* finish (trivial reply, unheard question) still gets the nudge.\n\n## Troubleshooting\n\n- **Nothing is ever spoken** — restart Claude Code after installing; hooks load\n  at startup. Then check `npx @amenophis1er/claude-voice test \"hello\"` produces audio at all.\n- **Short tasks are silent** — by design. Lower the `substantial` thresholds or\n  set `preset: \"verbose\"` to speak everything.\n- **No chimes on Linux/Windows** — expected for now; summaries still speak.\n- **Focus muting never mutes** — macOS asks for an Automation permission the\n  first time; if denied, claude-voice fails *open* (it speaks). Grant it in\n  System Settings → Privacy & Security → Automation.\n- **Dig deeper** — set `CLAUDE_VOICE_DEBUG=1`; every hook then appends the\n  reason something was (not) spoken to `$TMPDIR/claude-voice-debug.log`:\n  throttled, quiet hours, not substantial, provider fallback, playback errors.\n\n---\n\n## For developers\n\nEverything below is only relevant if you want to hack on claude-voice itself.\n\n### Running from source\n\n```bash\ngit clone https://github.com/amenophis1er/claude-voice.git && cd claude-voice\nnpm install\nnode src/cli.ts init      # wires hooks straight to the checkout's TypeScript\n```\n\nRunning the TS directly requires **Node ≥ 23.6** (type stripping). A `Makefile`\nwraps the npm scripts: `make init`, `make check`, `make say TEXT=\"hello\"`.\n\n### Build, test, dist\n\n```bash\nnpm run check     # typecheck + build + decision-logic tests\nnpm test          # just the tests (test/verify.mjs, no framework)\nnpm run build     # compile src/ → dist/ (plain JS, import paths rewritten)\n```\n\n`dist/` is committed on purpose: Claude Code plugin installs clone the repo and\nhave no build step, so `hooks/hooks.json` points at the compiled files. CI\nfails if `dist/` drifts from `src/` — run `npm run build` after changing\nsource.\n\nThe interesting logic is deliberately pure and tested: sanitization,\nclosing-sentence extraction, clamping, preset policies, transcript stats.\nAudio I/O is kept at the edges.\n\n### How it works\n\nSix Claude Code hooks share one dispatcher (`src/dispatch.ts`):\n\n- **`SessionStart`** injects an instruction teaching Claude to end substantial\n  tasks with one natural, speakable closing sentence (visible prose — an\n  earlier design hid it in an HTML comment, but Claude Code's terminal renderer\n  prints comments literally, so it leaked).\n- **`Stop`** reads the final message from the stable `last_assistant_message`\n  hook field, sanitizes it (code/paths/URLs/markdown stripped), extracts the\n  message's ending, clamps it (~350 chars), and speaks it. If Claude skipped\n  the instruction, the same extraction degrades to a cleaned tail of the\n  message.\n- **`Notification`** chimes/speaks a cue tailored to the notification type.\n  An `idle_prompt` is dropped while the session's last spoken summary is\n  fresh (10 min) — it would just repeat, less accurately, what was said.\n- **`UserPromptSubmit`** kills all in-flight audio for the session.\n- **`PostToolUse`** (verbose preset) speaks Claude's latest progress remark as\n  a mid-task milestone, gated hard: turn already substantial, no audio\n  currently playing, minimum interval, no repeats. The remark is read from the\n  transcript best-effort — if the internal format changes, milestones degrade\n  to silence, never to wrong speech.\n- **`SessionEnd`** removes the session's heartbeat file. Every other event\n  refreshes it; `announceProject: \"auto\"` prefixes spoken text with the\n  project name only while another session's heartbeat is fresh (< 30 min).\n\nSubstantiality is measured best-effort from the transcript JSONL (tool calls +\nduration since the last *human* message — tool results also arrive as\n`type:\"user\"` entries and must not count as turn boundaries). Transcript\nparsing is never load-bearing: if the internal format changes, summaries still\nwork.\n\n### Releasing\n\nReleases are CI-driven: bump the version in `package.json` + \n`.claude-plugin/plugin.json`, update `CHANGELOG.md`, then push a `v*` tag.\nThe release workflow runs the checks, publishes to npm (trusted publishing —\nno token), and creates the GitHub release with generated notes.\n\n### Adding a TTS provider\n\nTwo steps: implement the `TtsProvider` interface in a new file under\n`src/providers/` (synthesize text → audio file; never play it yourself), and\nregister it in `src/providers/registry.ts`. Playback and interruption stay\ncentralized in `speak.ts`.\n\n## License\n\nMIT\n","readmeFilename":"README.md"}