vibe-notify 0.1.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/LICENSE +21 -0
- package/README.md +112 -0
- package/dist/beep.d.ts +12 -0
- package/dist/beep.js +152 -0
- package/dist/beep.js.map +1 -0
- package/dist/cli.d.ts +4 -0
- package/dist/cli.js +71 -0
- package/dist/cli.js.map +1 -0
- package/dist/config.d.ts +8 -0
- package/dist/config.js +85 -0
- package/dist/config.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +105 -0
- package/dist/index.js.map +1 -0
- package/dist/player.d.ts +15 -0
- package/dist/player.js +147 -0
- package/dist/player.js.map +1 -0
- package/dist/types.d.ts +45 -0
- package/dist/types.js +3 -0
- package/dist/types.js.map +1 -0
- package/package.json +28 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 vibe-notify
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
# vibe-notify 🔊
|
|
2
|
+
|
|
3
|
+
Notification sounds for Claude Code sessions. Plays a customizable beep/jingle when Claude finishes responding — so you can step away and still know when your task is done.
|
|
4
|
+
|
|
5
|
+
## Quick Start
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
# Install globally
|
|
9
|
+
npm install -g vibe-notify
|
|
10
|
+
|
|
11
|
+
# Test it
|
|
12
|
+
vibe-notify victory
|
|
13
|
+
|
|
14
|
+
# Set up config
|
|
15
|
+
vibe-notify --init
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Or run without installing:
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
npx -y vibe-notify victory
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Built-in Sounds
|
|
25
|
+
|
|
26
|
+
| Sound | Description |
|
|
27
|
+
|-------|-------------|
|
|
28
|
+
| `short-beep` | Single short beep — quick acknowledgment |
|
|
29
|
+
| `double-beep` | Two quick beeps — "something finished" |
|
|
30
|
+
| `ascending` | Three rising tones — positive progression |
|
|
31
|
+
| `descending` | Three falling tones — winding down |
|
|
32
|
+
| `victory` | C-E-G-C arpeggio — celebratory jingle |
|
|
33
|
+
| `custom` | Play your own `.wav` file |
|
|
34
|
+
|
|
35
|
+
List them anytime: `vibe-notify --list`
|
|
36
|
+
|
|
37
|
+
## Configuration
|
|
38
|
+
|
|
39
|
+
Config file location (checked in order):
|
|
40
|
+
1. **Project-local**: `.vibe-notify.json` in your project root
|
|
41
|
+
2. **Global**: `~/.vibe-notify/config.json`
|
|
42
|
+
|
|
43
|
+
```json
|
|
44
|
+
{
|
|
45
|
+
"sound": "ascending",
|
|
46
|
+
"customFile": null,
|
|
47
|
+
"volume": 0.7,
|
|
48
|
+
"playback": {
|
|
49
|
+
"method": "auto"
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### Custom Sound File
|
|
55
|
+
|
|
56
|
+
```json
|
|
57
|
+
{
|
|
58
|
+
"sound": "custom",
|
|
59
|
+
"customFile": "C:\\Users\\You\\sounds\\done.wav",
|
|
60
|
+
"volume": 1.0
|
|
61
|
+
}
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## Claude Code Hook Setup
|
|
65
|
+
|
|
66
|
+
Add this to your `.claude/settings.json` (project or global) to auto-play when Claude finishes:
|
|
67
|
+
|
|
68
|
+
```json
|
|
69
|
+
{
|
|
70
|
+
"hooks": {
|
|
71
|
+
"Stop": [
|
|
72
|
+
{
|
|
73
|
+
"hooks": [
|
|
74
|
+
{
|
|
75
|
+
"type": "command",
|
|
76
|
+
"command": "npx",
|
|
77
|
+
"args": ["-y", "vibe-notify"],
|
|
78
|
+
"timeout": 15
|
|
79
|
+
}
|
|
80
|
+
]
|
|
81
|
+
}
|
|
82
|
+
]
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Replace `"npx", "-y", "vibe-notify"` with `"vibe-notify"` if installed globally. Add a sound name like `"victory"` to the args to override the config.
|
|
88
|
+
|
|
89
|
+
## CLI Reference
|
|
90
|
+
|
|
91
|
+
```
|
|
92
|
+
vibe-notify [options] [sound-name]
|
|
93
|
+
|
|
94
|
+
Options:
|
|
95
|
+
--help, -h Show help
|
|
96
|
+
--list, -l List available sounds
|
|
97
|
+
--config, -c Print config file path
|
|
98
|
+
--init Create default config file
|
|
99
|
+
--version, -v Show version
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
## How It Works
|
|
103
|
+
|
|
104
|
+
- **Zero runtime dependencies** — all sound generation is pure Node.js
|
|
105
|
+
- Built-in sounds are generated as WAV audio in-memory (sine waves with envelope)
|
|
106
|
+
- Playback uses native system players: PowerShell SoundPlayer (Windows), afplay (macOS), paplay/aplay (Linux)
|
|
107
|
+
- Falls back to `[System.Console]::Beep()` or terminal bell if WAV playback fails
|
|
108
|
+
- Temp files are cleaned up immediately after playback
|
|
109
|
+
|
|
110
|
+
## License
|
|
111
|
+
|
|
112
|
+
MIT
|
package/dist/beep.d.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { Pattern, Tone } from './types';
|
|
2
|
+
export declare const PATTERNS: Pattern[];
|
|
3
|
+
export declare function getPatternByName(name: string): Pattern | undefined;
|
|
4
|
+
/**
|
|
5
|
+
* Build a complete 16-bit PCM mono WAV buffer from a list of tones.
|
|
6
|
+
* Returns null if the pattern name is not found.
|
|
7
|
+
*/
|
|
8
|
+
export declare function buildPatternBuffer(patternName: string, volume?: number): Buffer | null;
|
|
9
|
+
/**
|
|
10
|
+
* Generate a WAV file buffer from an array of Tone objects.
|
|
11
|
+
*/
|
|
12
|
+
export declare function generateWav(tones: Tone[], sampleRate: number, volume: number): Buffer;
|
package/dist/beep.js
ADDED
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.PATTERNS = void 0;
|
|
4
|
+
exports.getPatternByName = getPatternByName;
|
|
5
|
+
exports.buildPatternBuffer = buildPatternBuffer;
|
|
6
|
+
exports.generateWav = generateWav;
|
|
7
|
+
// ── WAV constants ──────────────────────────────────────────────────────────
|
|
8
|
+
const SAMPLE_RATE = 44100;
|
|
9
|
+
const BITS_PER_SAMPLE = 16;
|
|
10
|
+
const NUM_CHANNELS = 1;
|
|
11
|
+
const BYTES_PER_SAMPLE = BITS_PER_SAMPLE / 8; // 2
|
|
12
|
+
// ── Built-in sound patterns ────────────────────────────────────────────────
|
|
13
|
+
exports.PATTERNS = [
|
|
14
|
+
{
|
|
15
|
+
name: 'short-beep',
|
|
16
|
+
description: 'A single short beep — quick task-complete acknowledgment',
|
|
17
|
+
tones: [{ frequency: 880, duration: 0.15 }],
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
name: 'double-beep',
|
|
21
|
+
description: 'Two quick beeps — "something just finished"',
|
|
22
|
+
tones: [
|
|
23
|
+
{ frequency: 660, duration: 0.1, gap: 0.08 },
|
|
24
|
+
{ frequency: 880, duration: 0.15 },
|
|
25
|
+
],
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
name: 'ascending',
|
|
29
|
+
description: 'Three rising tones — positive progression',
|
|
30
|
+
tones: [
|
|
31
|
+
{ frequency: 400, duration: 0.15, gap: 0.05 },
|
|
32
|
+
{ frequency: 600, duration: 0.15, gap: 0.05 },
|
|
33
|
+
{ frequency: 800, duration: 0.2 },
|
|
34
|
+
],
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
name: 'descending',
|
|
38
|
+
description: 'Three falling tones — task complete, winding down',
|
|
39
|
+
tones: [
|
|
40
|
+
{ frequency: 800, duration: 0.15, gap: 0.05 },
|
|
41
|
+
{ frequency: 600, duration: 0.15, gap: 0.05 },
|
|
42
|
+
{ frequency: 400, duration: 0.2 },
|
|
43
|
+
],
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
name: 'victory',
|
|
47
|
+
description: 'Victory jingle — C5-E5-G5-C6 arpeggio',
|
|
48
|
+
tones: [
|
|
49
|
+
{ frequency: 523.25, duration: 0.12, gap: 0.06 },
|
|
50
|
+
{ frequency: 659.25, duration: 0.12, gap: 0.06 },
|
|
51
|
+
{ frequency: 783.99, duration: 0.12, gap: 0.06 },
|
|
52
|
+
{ frequency: 1046.5, duration: 0.3 },
|
|
53
|
+
],
|
|
54
|
+
},
|
|
55
|
+
];
|
|
56
|
+
// ── Pattern lookup ─────────────────────────────────────────────────────────
|
|
57
|
+
function getPatternByName(name) {
|
|
58
|
+
return exports.PATTERNS.find((p) => p.name === name);
|
|
59
|
+
}
|
|
60
|
+
// ── WAV generation ─────────────────────────────────────────────────────────
|
|
61
|
+
/**
|
|
62
|
+
* Build a complete 16-bit PCM mono WAV buffer from a list of tones.
|
|
63
|
+
* Returns null if the pattern name is not found.
|
|
64
|
+
*/
|
|
65
|
+
function buildPatternBuffer(patternName, volume = 0.7) {
|
|
66
|
+
const pattern = getPatternByName(patternName);
|
|
67
|
+
if (!pattern)
|
|
68
|
+
return null;
|
|
69
|
+
return generateWav(pattern.tones, SAMPLE_RATE, clampVolume(volume));
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Generate a WAV file buffer from an array of Tone objects.
|
|
73
|
+
*/
|
|
74
|
+
function generateWav(tones, sampleRate, volume) {
|
|
75
|
+
// Calculate total samples needed
|
|
76
|
+
let totalSamples = 0;
|
|
77
|
+
for (const tone of tones) {
|
|
78
|
+
totalSamples += Math.ceil(tone.duration * sampleRate);
|
|
79
|
+
if (tone.gap && tone.gap > 0) {
|
|
80
|
+
totalSamples += Math.ceil(tone.gap * sampleRate);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
const dataSize = totalSamples * BYTES_PER_SAMPLE;
|
|
84
|
+
const headerSize = 44;
|
|
85
|
+
const buffer = Buffer.alloc(headerSize + dataSize);
|
|
86
|
+
// Write WAV header
|
|
87
|
+
writeWavHeader(buffer, dataSize, sampleRate);
|
|
88
|
+
// Generate audio samples
|
|
89
|
+
const samples = generateSamples(tones, sampleRate, volume, totalSamples);
|
|
90
|
+
// Write 16-bit PCM samples (little-endian)
|
|
91
|
+
let offset = headerSize;
|
|
92
|
+
for (let i = 0; i < totalSamples; i++) {
|
|
93
|
+
// Clamp to 16-bit range
|
|
94
|
+
const sample = Math.max(-32768, Math.min(32767, Math.round(samples[i] * 32767)));
|
|
95
|
+
buffer.writeInt16LE(sample, offset);
|
|
96
|
+
offset += 2;
|
|
97
|
+
}
|
|
98
|
+
return buffer;
|
|
99
|
+
}
|
|
100
|
+
// ── Internal helpers ───────────────────────────────────────────────────────
|
|
101
|
+
function clampVolume(v) {
|
|
102
|
+
return Math.max(0, Math.min(1, v));
|
|
103
|
+
}
|
|
104
|
+
function writeWavHeader(buffer, dataSize, sampleRate) {
|
|
105
|
+
const byteRate = sampleRate * NUM_CHANNELS * BYTES_PER_SAMPLE;
|
|
106
|
+
const blockAlign = NUM_CHANNELS * BYTES_PER_SAMPLE;
|
|
107
|
+
// RIFF header
|
|
108
|
+
buffer.write('RIFF', 0, 'ascii');
|
|
109
|
+
buffer.writeUInt32LE(36 + dataSize, 4); // ChunkSize
|
|
110
|
+
buffer.write('WAVE', 8, 'ascii');
|
|
111
|
+
// fmt sub-chunk
|
|
112
|
+
buffer.write('fmt ', 12, 'ascii');
|
|
113
|
+
buffer.writeUInt32LE(16, 16); // Subchunk1Size (PCM = 16)
|
|
114
|
+
buffer.writeUInt16LE(1, 20); // AudioFormat (PCM = 1)
|
|
115
|
+
buffer.writeUInt16LE(NUM_CHANNELS, 22);
|
|
116
|
+
buffer.writeUInt32LE(sampleRate, 24);
|
|
117
|
+
buffer.writeUInt32LE(byteRate, 28);
|
|
118
|
+
buffer.writeUInt16LE(blockAlign, 32);
|
|
119
|
+
buffer.writeUInt16LE(BITS_PER_SAMPLE, 34);
|
|
120
|
+
// data sub-chunk
|
|
121
|
+
buffer.write('data', 36, 'ascii');
|
|
122
|
+
buffer.writeUInt32LE(dataSize, 40);
|
|
123
|
+
}
|
|
124
|
+
function generateSamples(tones, sampleRate, volume, totalSamples) {
|
|
125
|
+
const samples = new Float32Array(totalSamples);
|
|
126
|
+
let offset = 0;
|
|
127
|
+
for (const tone of tones) {
|
|
128
|
+
const toneSamples = Math.ceil(tone.duration * sampleRate);
|
|
129
|
+
const attackSamples = Math.ceil(0.01 * sampleRate); // 10ms attack
|
|
130
|
+
const releaseSamples = Math.ceil(0.02 * sampleRate); // 20ms release
|
|
131
|
+
for (let i = 0; i < toneSamples; i++) {
|
|
132
|
+
const t = i / sampleRate;
|
|
133
|
+
let sample = Math.sin(2 * Math.PI * tone.frequency * t) * volume;
|
|
134
|
+
// Apply envelope to prevent clicks
|
|
135
|
+
if (i < attackSamples) {
|
|
136
|
+
sample *= i / attackSamples; // Linear fade-in
|
|
137
|
+
}
|
|
138
|
+
else if (i >= toneSamples - releaseSamples) {
|
|
139
|
+
sample *= (toneSamples - i) / releaseSamples; // Linear fade-out
|
|
140
|
+
}
|
|
141
|
+
samples[offset + i] = sample;
|
|
142
|
+
}
|
|
143
|
+
offset += toneSamples;
|
|
144
|
+
// Write silence for gap
|
|
145
|
+
if (tone.gap && tone.gap > 0) {
|
|
146
|
+
const gapSamples = Math.ceil(tone.gap * sampleRate);
|
|
147
|
+
offset += gapSamples; // Float32Array is already zero-filled
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
return samples;
|
|
151
|
+
}
|
|
152
|
+
//# sourceMappingURL=beep.js.map
|
package/dist/beep.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"beep.js","sourceRoot":"","sources":["../src/beep.ts"],"names":[],"mappings":"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"}
|
package/dist/cli.d.ts
ADDED
package/dist/cli.js
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.parseArgs = parseArgs;
|
|
4
|
+
exports.showHelp = showHelp;
|
|
5
|
+
exports.listSounds = listSounds;
|
|
6
|
+
const beep_1 = require("./beep");
|
|
7
|
+
// ── Public API ─────────────────────────────────────────────────────────────
|
|
8
|
+
function parseArgs(argv) {
|
|
9
|
+
const args = argv.slice(); // copy
|
|
10
|
+
if (args.length === 0) {
|
|
11
|
+
return { action: 'play' }; // Play configured sound
|
|
12
|
+
}
|
|
13
|
+
const first = args[0];
|
|
14
|
+
// Handle flags
|
|
15
|
+
switch (first) {
|
|
16
|
+
case '--help':
|
|
17
|
+
case '-h':
|
|
18
|
+
return { action: 'help' };
|
|
19
|
+
case '--list':
|
|
20
|
+
case '-l':
|
|
21
|
+
return { action: 'list' };
|
|
22
|
+
case '--config':
|
|
23
|
+
case '-c':
|
|
24
|
+
return { action: 'config' };
|
|
25
|
+
case '--init':
|
|
26
|
+
return { action: 'init' };
|
|
27
|
+
case '--version':
|
|
28
|
+
case '-v':
|
|
29
|
+
return { action: 'version' };
|
|
30
|
+
}
|
|
31
|
+
// Anything else is treated as a sound name
|
|
32
|
+
return { action: 'play', soundName: first };
|
|
33
|
+
}
|
|
34
|
+
// ── Display helpers ────────────────────────────────────────────────────────
|
|
35
|
+
function showHelp() {
|
|
36
|
+
console.log(`vibe-notify — Notification sounds for Claude Code
|
|
37
|
+
|
|
38
|
+
Usage:
|
|
39
|
+
vibe-notify [options] [sound-name]
|
|
40
|
+
|
|
41
|
+
Options:
|
|
42
|
+
--help, -h Show this help message
|
|
43
|
+
--list, -l List available built-in sounds
|
|
44
|
+
--config, -c Print the config file path
|
|
45
|
+
--init Create a default config file at ~/.vibe-notify/config.json
|
|
46
|
+
--version, -v Show version number
|
|
47
|
+
|
|
48
|
+
Arguments:
|
|
49
|
+
sound-name Play a specific sound (overrides config file):
|
|
50
|
+
${beep_1.PATTERNS.map((p) => p.name).join(', ')}
|
|
51
|
+
|
|
52
|
+
If no sound-name is given, plays the sound from the config file.
|
|
53
|
+
|
|
54
|
+
Examples:
|
|
55
|
+
vibe-notify victory Play the victory jingle
|
|
56
|
+
vibe-notify --list See all available sounds
|
|
57
|
+
vibe-notify --init Set up your config file
|
|
58
|
+
|
|
59
|
+
Config file: ~/.vibe-notify/config.json (or .vibe-notify.json in project root)
|
|
60
|
+
Claude Code hook: Add to .claude/settings.json → hooks.Stop
|
|
61
|
+
`);
|
|
62
|
+
}
|
|
63
|
+
function listSounds() {
|
|
64
|
+
console.log('Available built-in sounds:\n');
|
|
65
|
+
for (const pattern of beep_1.PATTERNS) {
|
|
66
|
+
console.log(` ${pattern.name.padEnd(14)} ${pattern.description}`);
|
|
67
|
+
}
|
|
68
|
+
console.log(`\n ${'custom'.padEnd(14)} Play a custom .wav file (set "customFile" in config)`);
|
|
69
|
+
console.log(`\nUse "vibe-notify <name>" to play one, or set "sound" in your config file.`);
|
|
70
|
+
}
|
|
71
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";;AAKA,8BAiCC;AAID,4BA2BC;AAED,gCAOC;AA7ED,iCAAkC;AAElC,8EAA8E;AAE9E,SAAgB,SAAS,CAAC,IAAc;IACtC,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC,OAAO;IAElC,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACtB,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC,wBAAwB;IACrD,CAAC;IAED,MAAM,KAAK,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;IAEtB,eAAe;IACf,QAAQ,KAAK,EAAE,CAAC;QACd,KAAK,QAAQ,CAAC;QACd,KAAK,IAAI;YACP,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC;QAE5B,KAAK,QAAQ,CAAC;QACd,KAAK,IAAI;YACP,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC;QAE5B,KAAK,UAAU,CAAC;QAChB,KAAK,IAAI;YACP,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC;QAE9B,KAAK,QAAQ;YACX,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC;QAE5B,KAAK,WAAW,CAAC;QACjB,KAAK,IAAI;YACP,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC;IACjC,CAAC;IAED,2CAA2C;IAC3C,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;AAC9C,CAAC;AAED,8EAA8E;AAE9E,SAAgB,QAAQ;IACtB,OAAO,CAAC,GAAG,CAAC;;;;;;;;;;;;;;qBAcO,eAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;;;;;;;;;;;CAW1D,CAAC,CAAC;AACH,CAAC;AAED,SAAgB,UAAU;IACxB,OAAO,CAAC,GAAG,CAAC,8BAA8B,CAAC,CAAC;IAC5C,KAAK,MAAM,OAAO,IAAI,eAAQ,EAAE,CAAC;QAC/B,OAAO,CAAC,GAAG,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC;IACrE,CAAC;IACD,OAAO,CAAC,GAAG,CAAC,OAAO,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,uDAAuD,CAAC,CAAC;IAC/F,OAAO,CAAC,GAAG,CAAC,6EAA6E,CAAC,CAAC;AAC7F,CAAC"}
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { VibeNotifyConfig } from './types';
|
|
2
|
+
export declare const DEFAULT_CONFIG: VibeNotifyConfig;
|
|
3
|
+
export declare function getConfigDir(): string;
|
|
4
|
+
export declare function getConfigPath(): string;
|
|
5
|
+
export declare function getConfigFilePath(): string;
|
|
6
|
+
export declare function loadConfig(): VibeNotifyConfig;
|
|
7
|
+
export declare function saveConfig(config: VibeNotifyConfig): void;
|
|
8
|
+
export declare function initConfig(): string;
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DEFAULT_CONFIG = void 0;
|
|
4
|
+
exports.getConfigDir = getConfigDir;
|
|
5
|
+
exports.getConfigPath = getConfigPath;
|
|
6
|
+
exports.getConfigFilePath = getConfigFilePath;
|
|
7
|
+
exports.loadConfig = loadConfig;
|
|
8
|
+
exports.saveConfig = saveConfig;
|
|
9
|
+
exports.initConfig = initConfig;
|
|
10
|
+
const fs_1 = require("fs");
|
|
11
|
+
const os_1 = require("os");
|
|
12
|
+
const path_1 = require("path");
|
|
13
|
+
// ── Defaults ───────────────────────────────────────────────────────────────
|
|
14
|
+
exports.DEFAULT_CONFIG = {
|
|
15
|
+
sound: 'short-beep',
|
|
16
|
+
customFile: null,
|
|
17
|
+
volume: 0.7,
|
|
18
|
+
playback: {
|
|
19
|
+
method: 'auto',
|
|
20
|
+
},
|
|
21
|
+
};
|
|
22
|
+
// ── Path resolution ────────────────────────────────────────────────────────
|
|
23
|
+
function getConfigDir() {
|
|
24
|
+
return (0, path_1.join)((0, os_1.homedir)(), '.vibe-notify');
|
|
25
|
+
}
|
|
26
|
+
function getConfigPath() {
|
|
27
|
+
// Project-local config takes priority
|
|
28
|
+
const local = (0, path_1.resolve)('.vibe-notify.json');
|
|
29
|
+
if ((0, fs_1.existsSync)(local)) {
|
|
30
|
+
return local;
|
|
31
|
+
}
|
|
32
|
+
// Fall back to global config
|
|
33
|
+
return (0, path_1.join)(getConfigDir(), 'config.json');
|
|
34
|
+
}
|
|
35
|
+
function getConfigFilePath() {
|
|
36
|
+
return getConfigPath();
|
|
37
|
+
}
|
|
38
|
+
// ── Load / Save ────────────────────────────────────────────────────────────
|
|
39
|
+
function loadConfig() {
|
|
40
|
+
const configPath = getConfigPath();
|
|
41
|
+
if (!(0, fs_1.existsSync)(configPath)) {
|
|
42
|
+
return { ...exports.DEFAULT_CONFIG };
|
|
43
|
+
}
|
|
44
|
+
try {
|
|
45
|
+
const raw = (0, fs_1.readFileSync)(configPath, 'utf-8');
|
|
46
|
+
const parsed = JSON.parse(raw);
|
|
47
|
+
return mergeConfig(exports.DEFAULT_CONFIG, parsed);
|
|
48
|
+
}
|
|
49
|
+
catch (err) {
|
|
50
|
+
console.error(`Warning: Could not read config at ${configPath}. Using defaults.`);
|
|
51
|
+
return { ...exports.DEFAULT_CONFIG };
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
function saveConfig(config) {
|
|
55
|
+
const configPath = getConfigPath();
|
|
56
|
+
const dir = getConfigDir();
|
|
57
|
+
if (!(0, fs_1.existsSync)(dir)) {
|
|
58
|
+
(0, fs_1.mkdirSync)(dir, { recursive: true });
|
|
59
|
+
}
|
|
60
|
+
(0, fs_1.writeFileSync)(configPath, JSON.stringify(config, null, 2), 'utf-8');
|
|
61
|
+
}
|
|
62
|
+
function initConfig() {
|
|
63
|
+
const configPath = getConfigPath();
|
|
64
|
+
const dir = getConfigDir();
|
|
65
|
+
if (!(0, fs_1.existsSync)(dir)) {
|
|
66
|
+
(0, fs_1.mkdirSync)(dir, { recursive: true });
|
|
67
|
+
}
|
|
68
|
+
if ((0, fs_1.existsSync)(configPath)) {
|
|
69
|
+
return configPath; // Already exists, don't overwrite
|
|
70
|
+
}
|
|
71
|
+
saveConfig({ ...exports.DEFAULT_CONFIG });
|
|
72
|
+
return configPath;
|
|
73
|
+
}
|
|
74
|
+
// ── Helpers ────────────────────────────────────────────────────────────────
|
|
75
|
+
function mergeConfig(defaults, overrides) {
|
|
76
|
+
return {
|
|
77
|
+
...defaults,
|
|
78
|
+
...overrides,
|
|
79
|
+
playback: {
|
|
80
|
+
...defaults.playback,
|
|
81
|
+
...(overrides.playback || {}),
|
|
82
|
+
},
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
const fs_1 = require("fs");
|
|
5
|
+
const cli_1 = require("./cli");
|
|
6
|
+
const config_1 = require("./config");
|
|
7
|
+
const beep_1 = require("./beep");
|
|
8
|
+
const player_1 = require("./player");
|
|
9
|
+
// Read version from package.json
|
|
10
|
+
let VERSION = '0.1.0';
|
|
11
|
+
try {
|
|
12
|
+
// When running from dist/, package.json is one level up
|
|
13
|
+
const pkg = JSON.parse((0, fs_1.readFileSync)(__dirname + '/../package.json', 'utf-8'));
|
|
14
|
+
VERSION = pkg.version || VERSION;
|
|
15
|
+
}
|
|
16
|
+
catch {
|
|
17
|
+
// Fallback version
|
|
18
|
+
}
|
|
19
|
+
async function main() {
|
|
20
|
+
const cli = (0, cli_1.parseArgs)(process.argv.slice(2));
|
|
21
|
+
// ── Info actions (no sound played) ───────────────────────────────────
|
|
22
|
+
switch (cli.action) {
|
|
23
|
+
case 'help':
|
|
24
|
+
(0, cli_1.showHelp)();
|
|
25
|
+
return;
|
|
26
|
+
case 'list':
|
|
27
|
+
(0, cli_1.listSounds)();
|
|
28
|
+
return;
|
|
29
|
+
case 'config':
|
|
30
|
+
console.log((0, config_1.getConfigFilePath)());
|
|
31
|
+
return;
|
|
32
|
+
case 'init': {
|
|
33
|
+
const path = (0, config_1.initConfig)();
|
|
34
|
+
console.log(`Config created at: ${path}`);
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
case 'version':
|
|
38
|
+
console.log(`vibe-notify v${VERSION}`);
|
|
39
|
+
return;
|
|
40
|
+
case 'play':
|
|
41
|
+
// Continue below
|
|
42
|
+
break;
|
|
43
|
+
}
|
|
44
|
+
// ── Play sound ───────────────────────────────────────────────────────
|
|
45
|
+
const config = (0, config_1.loadConfig)();
|
|
46
|
+
const soundName = cli.soundName || config.sound;
|
|
47
|
+
// Validate sound name
|
|
48
|
+
if (soundName !== 'custom' && !(0, beep_1.getPatternByName)(soundName)) {
|
|
49
|
+
console.error(`Unknown sound: "${soundName}"`);
|
|
50
|
+
console.error(`Use --list to see available sounds.`);
|
|
51
|
+
process.exit(1);
|
|
52
|
+
}
|
|
53
|
+
// ── Custom file playback ─────────────────────────────────────────────
|
|
54
|
+
if (soundName === 'custom') {
|
|
55
|
+
if (!config.customFile) {
|
|
56
|
+
console.error('Sound is set to "custom" but no customFile is configured.');
|
|
57
|
+
console.error(`Set "customFile" in ${(0, config_1.getConfigFilePath)()} to a .wav file path.`);
|
|
58
|
+
process.exit(1);
|
|
59
|
+
}
|
|
60
|
+
if (!(0, fs_1.existsSync)(config.customFile)) {
|
|
61
|
+
console.error(`Custom file not found: ${config.customFile}`);
|
|
62
|
+
process.exit(1);
|
|
63
|
+
}
|
|
64
|
+
try {
|
|
65
|
+
await (0, player_1.playFile)(config.customFile, config.playback.method);
|
|
66
|
+
}
|
|
67
|
+
catch (err) {
|
|
68
|
+
console.error(`Failed to play custom file: ${err.message}`);
|
|
69
|
+
process.exit(1);
|
|
70
|
+
}
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
// ── Built-in pattern playback ────────────────────────────────────────
|
|
74
|
+
const buffer = (0, beep_1.buildPatternBuffer)(soundName, config.volume);
|
|
75
|
+
if (buffer) {
|
|
76
|
+
try {
|
|
77
|
+
await (0, player_1.playBuffer)(buffer, config.playback.method);
|
|
78
|
+
}
|
|
79
|
+
catch (err) {
|
|
80
|
+
// WAV playback failed — try fallback beep
|
|
81
|
+
const pattern = (0, beep_1.getPatternByName)(soundName);
|
|
82
|
+
if (pattern) {
|
|
83
|
+
try {
|
|
84
|
+
await (0, player_1.fallbackBeep)(pattern.tones);
|
|
85
|
+
}
|
|
86
|
+
catch {
|
|
87
|
+
// Both methods failed — non-fatal, just warn
|
|
88
|
+
console.error(`Could not play sound: ${err.message}`);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
else {
|
|
94
|
+
// Buffer generation failed — fallback to system beep
|
|
95
|
+
const pattern = (0, beep_1.getPatternByName)(soundName);
|
|
96
|
+
if (pattern) {
|
|
97
|
+
await (0, player_1.fallbackBeep)(pattern.tones);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
main().catch((err) => {
|
|
102
|
+
console.error('vibe-notify error:', err.message);
|
|
103
|
+
process.exit(1);
|
|
104
|
+
});
|
|
105
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/player.d.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Tone, PlaybackMethod } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* Play a WAV buffer through the system audio output.
|
|
4
|
+
* Writes to a temp file, plays it, then cleans up.
|
|
5
|
+
*/
|
|
6
|
+
export declare function playBuffer(buffer: Buffer, method?: PlaybackMethod): Promise<void>;
|
|
7
|
+
/**
|
|
8
|
+
* Play a custom audio file (WAV) directly.
|
|
9
|
+
*/
|
|
10
|
+
export declare function playFile(filePath: string, method?: PlaybackMethod): Promise<void>;
|
|
11
|
+
/**
|
|
12
|
+
* Fallback: play tones using system beep (no WAV generation needed).
|
|
13
|
+
* Uses [System.Console]::Beep on Windows, terminal BEL on Unix.
|
|
14
|
+
*/
|
|
15
|
+
export declare function fallbackBeep(tones: Tone[]): Promise<void>;
|
package/dist/player.js
ADDED
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.playBuffer = playBuffer;
|
|
4
|
+
exports.playFile = playFile;
|
|
5
|
+
exports.fallbackBeep = fallbackBeep;
|
|
6
|
+
const child_process_1 = require("child_process");
|
|
7
|
+
const fs_1 = require("fs");
|
|
8
|
+
const os_1 = require("os");
|
|
9
|
+
const path_1 = require("path");
|
|
10
|
+
// ── Public API ─────────────────────────────────────────────────────────────
|
|
11
|
+
/**
|
|
12
|
+
* Play a WAV buffer through the system audio output.
|
|
13
|
+
* Writes to a temp file, plays it, then cleans up.
|
|
14
|
+
*/
|
|
15
|
+
async function playBuffer(buffer, method = 'auto') {
|
|
16
|
+
const tempFile = (0, path_1.join)((0, os_1.tmpdir)(), `vibe-notify-${Date.now()}.wav`);
|
|
17
|
+
try {
|
|
18
|
+
(0, fs_1.writeFileSync)(tempFile, buffer);
|
|
19
|
+
const platform = process.platform;
|
|
20
|
+
if (method === 'powershell' || (method === 'auto' && platform === 'win32')) {
|
|
21
|
+
await playWithPowerShell(tempFile);
|
|
22
|
+
}
|
|
23
|
+
else if (method === 'afplay' || (method === 'auto' && platform === 'darwin')) {
|
|
24
|
+
await playWithAfplay(tempFile);
|
|
25
|
+
}
|
|
26
|
+
else if (method === 'aplay' || (method === 'auto' && platform === 'linux')) {
|
|
27
|
+
await playWithLinux(tempFile);
|
|
28
|
+
}
|
|
29
|
+
else if (method === 'native') {
|
|
30
|
+
// "native" means try whatever the platform supports but don't use powershell/afplay/aplay
|
|
31
|
+
// On Windows this falls through to the beep fallback
|
|
32
|
+
throw new Error('Native method not supported for WAV playback');
|
|
33
|
+
}
|
|
34
|
+
else {
|
|
35
|
+
// Cross-platform fallback: try PowerShell even on non-Windows (WSL, etc.)
|
|
36
|
+
try {
|
|
37
|
+
await playWithPowerShell(tempFile);
|
|
38
|
+
}
|
|
39
|
+
catch {
|
|
40
|
+
await playWithLinux(tempFile);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
finally {
|
|
45
|
+
try {
|
|
46
|
+
(0, fs_1.unlinkSync)(tempFile);
|
|
47
|
+
}
|
|
48
|
+
catch {
|
|
49
|
+
// Temp file cleanup is best-effort
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Play a custom audio file (WAV) directly.
|
|
55
|
+
*/
|
|
56
|
+
async function playFile(filePath, method = 'auto') {
|
|
57
|
+
const platform = process.platform;
|
|
58
|
+
if (method === 'powershell' || (method === 'auto' && platform === 'win32')) {
|
|
59
|
+
await playWithPowerShell(filePath);
|
|
60
|
+
}
|
|
61
|
+
else if (method === 'afplay' || (method === 'auto' && platform === 'darwin')) {
|
|
62
|
+
await playWithAfplay(filePath);
|
|
63
|
+
}
|
|
64
|
+
else if (method === 'aplay' || (method === 'auto' && platform === 'linux')) {
|
|
65
|
+
await playWithLinux(filePath);
|
|
66
|
+
}
|
|
67
|
+
else {
|
|
68
|
+
await playWithPowerShell(filePath);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Fallback: play tones using system beep (no WAV generation needed).
|
|
73
|
+
* Uses [System.Console]::Beep on Windows, terminal BEL on Unix.
|
|
74
|
+
*/
|
|
75
|
+
async function fallbackBeep(tones) {
|
|
76
|
+
const platform = process.platform;
|
|
77
|
+
for (const tone of tones) {
|
|
78
|
+
if (platform === 'win32') {
|
|
79
|
+
await execPromise('powershell', [
|
|
80
|
+
'-NoProfile',
|
|
81
|
+
'-NonInteractive',
|
|
82
|
+
'-Command',
|
|
83
|
+
`[System.Console]::Beep(${tone.frequency}, ${Math.round(tone.duration * 1000)})`,
|
|
84
|
+
]);
|
|
85
|
+
}
|
|
86
|
+
else {
|
|
87
|
+
// Terminal bell character
|
|
88
|
+
process.stderr.write('\x07');
|
|
89
|
+
await delay(tone.duration * 1000);
|
|
90
|
+
}
|
|
91
|
+
if (tone.gap && tone.gap > 0) {
|
|
92
|
+
await delay(tone.gap * 1000);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
// ── Platform-specific players ──────────────────────────────────────────────
|
|
97
|
+
async function playWithPowerShell(filePath) {
|
|
98
|
+
const escaped = filePath.replace(/'/g, "''");
|
|
99
|
+
await execPromise('powershell', [
|
|
100
|
+
'-NoProfile',
|
|
101
|
+
'-NonInteractive',
|
|
102
|
+
'-Command',
|
|
103
|
+
`$p = New-Object System.Media.SoundPlayer('${escaped}'); $p.PlaySync()`,
|
|
104
|
+
]);
|
|
105
|
+
}
|
|
106
|
+
async function playWithAfplay(filePath) {
|
|
107
|
+
await execPromise('afplay', [filePath]);
|
|
108
|
+
}
|
|
109
|
+
async function playWithLinux(filePath) {
|
|
110
|
+
// Try PulseAudio first, fallback to ALSA
|
|
111
|
+
try {
|
|
112
|
+
await execPromise('paplay', [filePath]);
|
|
113
|
+
}
|
|
114
|
+
catch {
|
|
115
|
+
try {
|
|
116
|
+
await execPromise('aplay', [filePath]);
|
|
117
|
+
}
|
|
118
|
+
catch {
|
|
119
|
+
// Last resort: try ffplay if available
|
|
120
|
+
await execPromise('ffplay', ['-nodisp', '-autoexit', '-loglevel', 'quiet', filePath]);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
// ── Utilities ──────────────────────────────────────────────────────────────
|
|
125
|
+
function execPromise(command, args) {
|
|
126
|
+
return new Promise((resolve, reject) => {
|
|
127
|
+
const proc = (0, child_process_1.spawn)(command, args, {
|
|
128
|
+
stdio: 'ignore',
|
|
129
|
+
windowsHide: true,
|
|
130
|
+
});
|
|
131
|
+
proc.on('close', (code) => {
|
|
132
|
+
if (code === 0) {
|
|
133
|
+
resolve();
|
|
134
|
+
}
|
|
135
|
+
else {
|
|
136
|
+
reject(new Error(`${command} exited with code ${code}`));
|
|
137
|
+
}
|
|
138
|
+
});
|
|
139
|
+
proc.on('error', (err) => {
|
|
140
|
+
reject(err);
|
|
141
|
+
});
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
function delay(ms) {
|
|
145
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
146
|
+
}
|
|
147
|
+
//# sourceMappingURL=player.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"player.js","sourceRoot":"","sources":["../src/player.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/** A single tone in a sound pattern */
|
|
2
|
+
export interface Tone {
|
|
3
|
+
/** Frequency in Hz */
|
|
4
|
+
frequency: number;
|
|
5
|
+
/** Duration in seconds */
|
|
6
|
+
duration: number;
|
|
7
|
+
/** Silence after this tone in seconds (optional) */
|
|
8
|
+
gap?: number;
|
|
9
|
+
}
|
|
10
|
+
/** A named sound pattern composed of tones */
|
|
11
|
+
export interface Pattern {
|
|
12
|
+
name: string;
|
|
13
|
+
description: string;
|
|
14
|
+
tones: Tone[];
|
|
15
|
+
}
|
|
16
|
+
/** Supported playback methods */
|
|
17
|
+
export type PlaybackMethod = 'auto' | 'powershell' | 'afplay' | 'aplay' | 'native';
|
|
18
|
+
/** Config file shape */
|
|
19
|
+
export interface VibeNotifyConfig {
|
|
20
|
+
/** Built-in pattern name, or "custom" for a custom file */
|
|
21
|
+
sound: string;
|
|
22
|
+
/** Absolute path to a .wav file (used when sound === "custom") */
|
|
23
|
+
customFile: string | null;
|
|
24
|
+
/** Volume 0.0–1.0 */
|
|
25
|
+
volume: number;
|
|
26
|
+
/** Playback settings */
|
|
27
|
+
playback: {
|
|
28
|
+
method: PlaybackMethod;
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
/** CLI action after parsing args */
|
|
32
|
+
export type CliAction = {
|
|
33
|
+
action: 'help';
|
|
34
|
+
} | {
|
|
35
|
+
action: 'list';
|
|
36
|
+
} | {
|
|
37
|
+
action: 'config';
|
|
38
|
+
} | {
|
|
39
|
+
action: 'init';
|
|
40
|
+
} | {
|
|
41
|
+
action: 'version';
|
|
42
|
+
} | {
|
|
43
|
+
action: 'play';
|
|
44
|
+
soundName?: string;
|
|
45
|
+
};
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
|
package/package.json
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "vibe-notify",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Notification sounds for Claude Code completions — customizable beeps when your session finishes",
|
|
5
|
+
"keywords": ["claude", "claude-code", "notification", "sound", "beep", "alert"],
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"author": "guant0u",
|
|
8
|
+
"repository": "github:GuanT0u/vibe-notify",
|
|
9
|
+
"homepage": "https://github.com/GuanT0u/vibe-notify#readme",
|
|
10
|
+
"main": "dist/index.js",
|
|
11
|
+
"bin": {
|
|
12
|
+
"vibe-notify": "dist/index.js"
|
|
13
|
+
},
|
|
14
|
+
"files": [
|
|
15
|
+
"dist/",
|
|
16
|
+
"README.md",
|
|
17
|
+
"LICENSE"
|
|
18
|
+
],
|
|
19
|
+
"scripts": {
|
|
20
|
+
"build": "tsc",
|
|
21
|
+
"prepublishOnly": "npm run build",
|
|
22
|
+
"lint": "tsc --noEmit"
|
|
23
|
+
},
|
|
24
|
+
"devDependencies": {
|
|
25
|
+
"@types/node": "^18.19.0",
|
|
26
|
+
"typescript": "^5.3.0"
|
|
27
|
+
}
|
|
28
|
+
}
|