oopsx 0.0.1 → 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +54 -36
  2. package/bin/merr.js +54 -6
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -2,45 +2,66 @@
2
2
 
3
3
  A CLI that plays a meme sound when your terminal command fails.
4
4
 
5
- Wrap any command with `oopsx`. If it fails (non-zero exit code), you hear a sound. If it passes, nothing happens. Your original output and exit code are preserved.
6
-
7
- ```
8
- $ oopsx git puhs origin main
9
- fatal: 'puhs' is not a git command.
10
- 🔊 *plays sound*
11
- ```
12
-
13
5
  ## Install
14
6
 
15
7
  ```bash
16
8
  npm install -g oopsx
17
9
  ```
18
10
 
19
- Or run without installing:
11
+ ## Setup (recommended)
12
+
13
+ Add this to your `~/.zshrc`:
20
14
 
21
15
  ```bash
22
- npx oopsx ls /nonexistent/path
16
+ eval "$(oopsx init zsh)"
23
17
  ```
24
18
 
25
- Or via curl (macOS / Linux):
19
+ Or for bash, add to `~/.bashrc`:
26
20
 
27
21
  ```bash
28
- curl -fsSL https://raw.githubusercontent.com/devesh760/oopsx/main/install.sh | bash
22
+ eval "$(oopsx init bash)"
23
+ ```
24
+
25
+ Restart your terminal. Now every failed command plays a sound automatically — no prefix needed.
26
+
27
+ ```
28
+ $ git puhs origin main
29
+ fatal: 'puhs' is not a git command.
30
+ 🔊 *sound plays*
31
+
32
+ $ ls /does/not/exist
33
+ ls: /does/not/exist: No such file or directory
34
+ 🔊 *sound plays*
35
+
36
+ $ echo "hello"
37
+ hello
38
+ # silence — command passed
29
39
  ```
30
40
 
31
- ## Usage
41
+ ## Wrap a single command
42
+
43
+ If you don't want the shell hook, you can wrap individual commands:
32
44
 
33
45
  ```bash
34
- oopsx <command>
46
+ oopsx ls /does/not/exist
47
+ oopsx npm test
48
+ oopsx --sound ~/bruh.mp3 make build
35
49
  ```
36
50
 
51
+ ## Custom sounds
52
+
37
53
  ```bash
38
- oopsx ls /does/not/exist # plays default sound on failure
39
- oopsx --sound ~/bruh.mp3 npm test # use a custom sound
40
- oopsx --url https://x.com/f.mp3 make build # download + cache a sound
41
- oopsx --volume 50 python script.py # set volume (0-100)
42
- oopsx --sound ~/oof.mp3 --set-default echo hi # save as default
43
- oopsx --once cargo build # play only once per session
54
+ # Use a local file
55
+ oopsx --sound ~/bruh.mp3 npm test
56
+
57
+ # Download from URL (cached automatically)
58
+ oopsx --url https://example.com/fail.mp3 make build
59
+
60
+ # Save a sound as the new default
61
+ oopsx --sound ~/oof.mp3 --set-default echo hi
62
+
63
+ # Set volume (0-100)
64
+ oopsx --volume 50 cargo build
44
65
  ```
45
66
 
46
67
  ## Options
@@ -53,27 +74,22 @@ oopsx --once cargo build # play only once per session
53
74
  | `--set-default` | Save the resolved sound as the new default |
54
75
  | `--once` | Play sound only once per shell session |
55
76
 
56
- ## How it works
57
-
58
- 1. Runs your command with inherited stdio — you see all output as normal.
59
- 2. If exit code is `0`, does nothing.
60
- 3. If exit code is non-zero, plays a sound.
61
- 4. Exits with the **same exit code** as your command.
77
+ ## Commands
62
78
 
63
- A default sound is bundled out of the box. You can replace it with `--sound <file> --set-default`.
79
+ | Command | Description |
80
+ | --------------- | ------------------------------------------------ |
81
+ | `oopsx init zsh` | Print shell hook for zsh |
82
+ | `oopsx init bash` | Print shell hook for bash |
83
+ | `oopsx play` | Play the sound (used by the hook internally) |
84
+ | `oopsx <cmd>` | Wrap a command and play sound on failure |
64
85
 
65
- Sound priority: `--sound` > `--url` > `~/.merr/default.mp3`
86
+ ## How it works
66
87
 
67
- ## Config
88
+ **Shell hook mode**: After each command, the hook checks the exit code. If non-zero, it plays the sound in the background so it doesn't block your prompt.
68
89
 
69
- Stored in `~/.merr/`:
90
+ **Wrapper mode**: Runs your command, checks exit code, plays sound if it failed, then exits with the same code.
70
91
 
71
- ```
72
- ~/.merr/
73
- ├── config.json # volume
74
- ├── default.mp3 # default sound
75
- └── sounds/ # cached URL downloads
76
- ```
92
+ A default sound is bundled. Config and cached sounds live in `~/.merr/`.
77
93
 
78
94
  ## Platform support
79
95
 
@@ -90,6 +106,8 @@ npm uninstall -g oopsx
90
106
  rm -rf ~/.merr
91
107
  ```
92
108
 
109
+ Remove the `eval "$(oopsx init ...)"` line from your shell rc file.
110
+
93
111
  ## License
94
112
 
95
113
  MIT
package/bin/merr.js CHANGED
@@ -12,8 +12,60 @@ const program = new Command();
12
12
  program
13
13
  .name("oopsx")
14
14
  .description("Play a meme sound when your terminal command fails")
15
- .version("1.0.0")
16
- .argument("<command...>", "Shell command to execute")
15
+ .version("1.0.0");
16
+
17
+ // --- `oopsx init <shell>` — output shell hook snippet ---
18
+ program
19
+ .command("init <shell>")
20
+ .description("Print shell hook to auto-play sound on errors (zsh or bash)")
21
+ .action((shell) => {
22
+ const normalized = shell.toLowerCase().trim();
23
+
24
+ if (normalized === "zsh") {
25
+ console.log(`
26
+ __oopsx_precmd() {
27
+ local exit_code=$?
28
+ [[ $exit_code -ne 0 ]] && oopsx play &>/dev/null &
29
+ return $exit_code
30
+ }
31
+ precmd_functions+=(__oopsx_precmd)
32
+ `.trim());
33
+ } else if (normalized === "bash") {
34
+ console.log(`
35
+ __oopsx_prompt_command() {
36
+ local exit_code=$?
37
+ [[ $exit_code -ne 0 ]] && oopsx play &>/dev/null &
38
+ return $exit_code
39
+ }
40
+ PROMPT_COMMAND="__oopsx_prompt_command;\${PROMPT_COMMAND}"
41
+ `.trim());
42
+ } else {
43
+ console.error(`Unsupported shell: ${shell}. Use "zsh" or "bash".`);
44
+ process.exit(1);
45
+ }
46
+ });
47
+
48
+ // --- `oopsx play` — just play the sound (used by shell hook) ---
49
+ program
50
+ .command("play")
51
+ .description("Play the error sound (used internally by the shell hook)")
52
+ .action(async () => {
53
+ const config = readConfig();
54
+ const soundFile = await resolveSound({});
55
+
56
+ if (!soundFile) process.exit(0);
57
+
58
+ try {
59
+ await playAudio(soundFile, config.volume ?? 80);
60
+ } catch {
61
+ // silent — this runs in background, don't pollute the terminal
62
+ }
63
+ });
64
+
65
+ // --- `oopsx run <command...>` — wrap a single command (original behavior) ---
66
+ program
67
+ .command("run <command...>", { isDefault: true })
68
+ .description("Execute a command and play sound on failure")
17
69
  .option("--sound <path>", "Use a local sound file (mp3/wav)")
18
70
  .option("--url <url>", "Download and cache a sound from a URL")
19
71
  .option("--volume <number>", "Playback volume 0–100", parseInt)
@@ -24,7 +76,6 @@ program
24
76
  const config = readConfig();
25
77
  const volume = options.volume ?? config.volume ?? 80;
26
78
 
27
- // Persist volume if explicitly provided
28
79
  if (options.volume !== undefined) {
29
80
  setVolume(options.volume);
30
81
  }
@@ -35,7 +86,6 @@ program
35
86
  process.exit(0);
36
87
  }
37
88
 
38
- // --once: skip if already played in this shell session
39
89
  if (options.once && process.env[SESSION_KEY]) {
40
90
  process.exit(exitCode);
41
91
  }
@@ -46,7 +96,6 @@ program
46
96
  process.exit(exitCode);
47
97
  }
48
98
 
49
- // --set-default: persist the resolved sound
50
99
  if (options.setDefault) {
51
100
  setDefault(soundFile);
52
101
  }
@@ -57,7 +106,6 @@ program
57
106
  console.error(`Sound playback failed: ${err.message}`);
58
107
  }
59
108
 
60
- // Mark as played for --once (only useful if parent reads env, but we set it anyway)
61
109
  if (options.once) {
62
110
  process.env[SESSION_KEY] = "1";
63
111
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "oopsx",
3
- "version": "0.0.1",
3
+ "version": "0.0.2",
4
4
  "description": "Play a meme sound when your terminal command fails",
5
5
  "type": "module",
6
6
  "bin": {