oopsx 0.0.2 → 0.0.3

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 +5 -89
  2. package/bin/merr.js +74 -0
  3. package/package.json +4 -1
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # oopsx
2
2
 
3
- A CLI that plays a meme sound when your terminal command fails.
3
+ Play a meme sound when your terminal command fails. Comes with a default sound out of the box.
4
4
 
5
5
  ## Install
6
6
 
@@ -8,106 +8,22 @@ A CLI that plays a meme sound when your terminal command fails.
8
8
  npm install -g oopsx
9
9
  ```
10
10
 
11
- ## Setup (recommended)
11
+ Restart your terminal. Every failed command now plays a sound.
12
12
 
13
- Add this to your `~/.zshrc`:
13
+ ## Custom sound
14
14
 
15
15
  ```bash
16
- eval "$(oopsx init zsh)"
16
+ oopsx --sound ~/bruh.mp3 --set-default echo hi
17
17
  ```
18
18
 
19
- Or for bash, add to `~/.bashrc`:
20
-
21
- ```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
39
- ```
40
-
41
- ## Wrap a single command
42
-
43
- If you don't want the shell hook, you can wrap individual commands:
44
-
45
- ```bash
46
- oopsx ls /does/not/exist
47
- oopsx npm test
48
- oopsx --sound ~/bruh.mp3 make build
49
- ```
50
-
51
- ## Custom sounds
52
-
53
- ```bash
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
65
- ```
66
-
67
- ## Options
68
-
69
- | Option | Description |
70
- | ------------------- | --------------------------------------------- |
71
- | `--sound <path>` | Use a local `.mp3` or `.wav` file |
72
- | `--url <url>` | Download and cache a sound from a URL |
73
- | `--volume <0-100>` | Playback volume (default: `80`) |
74
- | `--set-default` | Save the resolved sound as the new default |
75
- | `--once` | Play sound only once per shell session |
76
-
77
- ## Commands
78
-
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 |
85
-
86
- ## How it works
87
-
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.
89
-
90
- **Wrapper mode**: Runs your command, checks exit code, plays sound if it failed, then exits with the same code.
91
-
92
- A default sound is bundled. Config and cached sounds live in `~/.merr/`.
93
-
94
- ## Platform support
95
-
96
- | Platform | Backend |
97
- | -------- | -------------------- |
98
- | macOS | `afplay` (built-in) |
99
- | Linux | `aplay` / `mpg123` |
100
- | Windows | PowerShell fallback |
101
-
102
19
  ## Uninstall
103
20
 
104
21
  ```bash
22
+ oopsx remove
105
23
  npm uninstall -g oopsx
106
24
  rm -rf ~/.merr
107
25
  ```
108
26
 
109
- Remove the `eval "$(oopsx init ...)"` line from your shell rc file.
110
-
111
27
  ## License
112
28
 
113
29
  MIT
package/bin/merr.js CHANGED
@@ -1,10 +1,33 @@
1
1
  #!/usr/bin/env node
2
2
 
3
+ import { existsSync, readFileSync, appendFileSync, writeFileSync } from "node:fs";
4
+ import { homedir } from "node:os";
5
+ import { join } from "node:path";
3
6
  import { Command } from "commander";
4
7
  import { runCommand } from "../src/runner.js";
5
8
  import { resolveSound, playAudio, setDefault, setVolume } from "../src/sound.js";
6
9
  import { readConfig } from "../src/config.js";
7
10
 
11
+ const HOOK_MARKER = "# oopsx shell hook";
12
+
13
+ const getShellRc = () => {
14
+ const shell = (process.env.SHELL || "").toLowerCase();
15
+ if (shell.endsWith("zsh")) return { file: join(homedir(), ".zshrc"), type: "zsh" };
16
+ if (shell.endsWith("bash")) return { file: join(homedir(), ".bashrc"), type: "bash" };
17
+ return null;
18
+ };
19
+
20
+ const hookSnippet = (type) => {
21
+ if (type === "zsh") {
22
+ return `
23
+ ${HOOK_MARKER}
24
+ eval "$(oopsx init zsh)"`;
25
+ }
26
+ return `
27
+ ${HOOK_MARKER}
28
+ eval "$(oopsx init bash)"`;
29
+ };
30
+
8
31
  const SESSION_KEY = `OOPSX_PLAYED_${process.ppid}`;
9
32
 
10
33
  const program = new Command();
@@ -45,6 +68,57 @@ PROMPT_COMMAND="__oopsx_prompt_command;\${PROMPT_COMMAND}"
45
68
  }
46
69
  });
47
70
 
71
+ // --- `oopsx setup` — auto-add hook to shell rc file ---
72
+ program
73
+ .command("setup")
74
+ .description("Automatically add the shell hook to your .zshrc or .bashrc")
75
+ .action(() => {
76
+ const rc = getShellRc();
77
+ if (!rc) {
78
+ console.error("Could not detect your shell. Manually add: eval \"$(oopsx init zsh)\" to your rc file.");
79
+ process.exit(1);
80
+ }
81
+
82
+ if (existsSync(rc.file)) {
83
+ const contents = readFileSync(rc.file, "utf-8");
84
+ if (contents.includes(HOOK_MARKER)) {
85
+ console.log(`Already set up in ${rc.file}`);
86
+ return;
87
+ }
88
+ }
89
+
90
+ appendFileSync(rc.file, hookSnippet(rc.type), "utf-8");
91
+ console.log(`Added oopsx hook to ${rc.file}`);
92
+ console.log("Restart your terminal or run: source " + rc.file);
93
+ });
94
+
95
+ // --- `oopsx remove` — remove hook from shell rc file ---
96
+ program
97
+ .command("remove")
98
+ .description("Remove the shell hook from your .zshrc or .bashrc")
99
+ .action(() => {
100
+ const rc = getShellRc();
101
+ if (!rc || !existsSync(rc.file)) {
102
+ console.log("Nothing to remove.");
103
+ return;
104
+ }
105
+
106
+ const contents = readFileSync(rc.file, "utf-8");
107
+ if (!contents.includes(HOOK_MARKER)) {
108
+ console.log("No oopsx hook found in " + rc.file);
109
+ return;
110
+ }
111
+
112
+ const cleaned = contents
113
+ .split("\n")
114
+ .filter((line) => !line.includes("oopsx") && line !== HOOK_MARKER)
115
+ .join("\n");
116
+
117
+ writeFileSync(rc.file, cleaned, "utf-8");
118
+ console.log(`Removed oopsx hook from ${rc.file}`);
119
+ console.log("Restart your terminal or run: source " + rc.file);
120
+ });
121
+
48
122
  // --- `oopsx play` — just play the sound (used by shell hook) ---
49
123
  program
50
124
  .command("play")
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "oopsx",
3
- "version": "0.0.2",
3
+ "version": "0.0.3",
4
4
  "description": "Play a meme sound when your terminal command fails",
5
5
  "type": "module",
6
6
  "bin": {
@@ -32,6 +32,9 @@
32
32
  "bugs": {
33
33
  "url": "https://github.com/devesh760/oopsx/issues"
34
34
  },
35
+ "scripts": {
36
+ "postinstall": "node bin/merr.js setup"
37
+ },
35
38
  "dependencies": {
36
39
  "commander": "^12.1.0",
37
40
  "play-sound": "^1.1.6"