opencode-plugin-boops 2.3.0 → 2.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -0
- package/cli/browse +12 -46
- package/index.ts +11 -4
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -69,6 +69,8 @@ The plugin listens to OpenCode events and plays sounds based on your configurati
|
|
|
69
69
|
- **`permission.asked`** - AI needs permission → gentle "relax" chime
|
|
70
70
|
- **`session.error`** - An error occurs → friendly "magic" alert
|
|
71
71
|
|
|
72
|
+
**Instant config reload:** The config is reloaded on every event, so changes take effect immediately without restarting OpenCode! Edit your config, trigger an event, and hear the new sound instantly.
|
|
73
|
+
|
|
72
74
|
Sounds are downloaded once on first use and cached in `~/.cache/opencode/boops/` for instant playback.
|
|
73
75
|
|
|
74
76
|
## Configuration
|
package/cli/browse
CHANGED
|
@@ -127,7 +127,7 @@ function loadCurrentConfig() {
|
|
|
127
127
|
}
|
|
128
128
|
}
|
|
129
129
|
|
|
130
|
-
// Save config to boops.toml
|
|
130
|
+
// Save config to boops.toml
|
|
131
131
|
function saveConfig(config) {
|
|
132
132
|
if (!PLUGIN_INSTALLED) {
|
|
133
133
|
console.error("\n⚠️ Cannot save: Plugin not installed");
|
|
@@ -138,48 +138,14 @@ function saveConfig(config) {
|
|
|
138
138
|
|
|
139
139
|
const configPath = join(homedir(), ".config", "opencode", "plugins", "boops", "boops.toml");
|
|
140
140
|
|
|
141
|
-
//
|
|
142
|
-
|
|
143
|
-
if (existsSync(configPath)) {
|
|
144
|
-
existingContent = readFileSync(configPath, "utf-8");
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
// Parse existing [sounds] section to merge with new values
|
|
148
|
-
const existingSounds = {};
|
|
149
|
-
if (existingContent) {
|
|
150
|
-
const lines = existingContent.split("\n");
|
|
151
|
-
let inSoundsSection = false;
|
|
152
|
-
|
|
153
|
-
for (const line of lines) {
|
|
154
|
-
const trimmed = line.trim();
|
|
155
|
-
|
|
156
|
-
if (trimmed === "[sounds]") {
|
|
157
|
-
inSoundsSection = true;
|
|
158
|
-
continue;
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
if (trimmed.startsWith("[") && trimmed !== "[sounds]") {
|
|
162
|
-
inSoundsSection = false;
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
if (inSoundsSection && !trimmed.startsWith("#") && trimmed) {
|
|
166
|
-
const match = trimmed.match(/^"?([^"=]+)"?\s*=\s*"?([^"#]+)"?/);
|
|
167
|
-
if (match) {
|
|
168
|
-
const [, key, value] = match;
|
|
169
|
-
existingSounds[key.trim()] = value.trim().replace(/"/g, "");
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
// Merge new sounds with existing
|
|
176
|
-
const mergedSounds = { ...existingSounds, ...(config.sounds || {}) };
|
|
177
|
-
|
|
178
|
-
// Write back, preserving the header
|
|
141
|
+
// Write config as-is (don't merge with file, since config was loaded from file)
|
|
142
|
+
// This allows deletions to work properly
|
|
179
143
|
let content = "# OpenCode Boops Plugin Configuration\n# Sounds can be local file paths OR URLs (automatically downloaded and cached)\n\n[sounds]\n";
|
|
180
144
|
|
|
181
|
-
|
|
182
|
-
|
|
145
|
+
if (config.sounds) {
|
|
146
|
+
for (const [event, sound] of Object.entries(config.sounds).sort()) {
|
|
147
|
+
content += `"${event}" = "${sound}"\n`;
|
|
148
|
+
}
|
|
183
149
|
}
|
|
184
150
|
|
|
185
151
|
writeFileSync(configPath, content);
|
|
@@ -1274,7 +1240,7 @@ async function browse() {
|
|
|
1274
1240
|
let controls;
|
|
1275
1241
|
if (state.pickerMode) {
|
|
1276
1242
|
controls = PLUGIN_INSTALLED
|
|
1277
|
-
? ' \x1b[38;5;240m↑/↓ select enter play
|
|
1243
|
+
? ' \x1b[38;5;240m↑/↓ select enter play a assign d unassign ←/esc close\x1b[0m'
|
|
1278
1244
|
: ' \x1b[38;5;240m↑/↓ select event enter play ←/esc close \x1b[38;5;208m(save disabled)\x1b[0m';
|
|
1279
1245
|
} else {
|
|
1280
1246
|
controls = ' \x1b[38;5;240m↑/↓ navigate ←/→ tags / search s assign enter play q quit\x1b[0m';
|
|
@@ -1925,18 +1891,18 @@ async function browse() {
|
|
|
1925
1891
|
}
|
|
1926
1892
|
}
|
|
1927
1893
|
return;
|
|
1928
|
-
} else if (key === '
|
|
1929
|
-
//
|
|
1894
|
+
} else if (key === 'a') {
|
|
1895
|
+
// 'a' - assign sound to selected event (auto-saves)
|
|
1930
1896
|
const config = loadCurrentConfig();
|
|
1931
1897
|
const event = availableEvents[state.pickerSelectedEvent];
|
|
1932
1898
|
|
|
1933
1899
|
if (!config.sounds) config.sounds = {};
|
|
1934
1900
|
config.sounds[event] = state.pickerSound.name; // Save friendly name, not ID
|
|
1935
1901
|
|
|
1936
|
-
//
|
|
1902
|
+
// Auto-save to config file
|
|
1937
1903
|
saveConfig(config);
|
|
1938
1904
|
|
|
1939
|
-
// Stay in picker mode
|
|
1905
|
+
// Stay in picker mode to assign more
|
|
1940
1906
|
render();
|
|
1941
1907
|
return;
|
|
1942
1908
|
} else if (key === 'd') {
|
package/index.ts
CHANGED
|
@@ -68,9 +68,9 @@ export const BoopsPlugin: Plugin = async ({ client }) => {
|
|
|
68
68
|
const loadConfig = async (): Promise<BoopsConfig> => {
|
|
69
69
|
let config: BoopsConfig = {
|
|
70
70
|
sounds: {
|
|
71
|
-
"session.idle": "
|
|
72
|
-
"permission.asked": "
|
|
73
|
-
"session.error": "
|
|
71
|
+
"session.idle": "pristine",
|
|
72
|
+
"permission.asked": "relax",
|
|
73
|
+
"session.error": "magic",
|
|
74
74
|
},
|
|
75
75
|
fallbacks: {
|
|
76
76
|
default: "/usr/share/sounds/alsa/Front_Center.wav"
|
|
@@ -96,10 +96,13 @@ export const BoopsPlugin: Plugin = async ({ client }) => {
|
|
|
96
96
|
return config
|
|
97
97
|
}
|
|
98
98
|
|
|
99
|
+
// Load initial config (will be reloaded on every event for instant updates)
|
|
99
100
|
let config = await loadConfig()
|
|
100
101
|
|
|
101
102
|
// Detect available sound player
|
|
102
103
|
const detectPlayer = async (): Promise<string> => {
|
|
104
|
+
// Reload config to check for player changes
|
|
105
|
+
config = await loadConfig()
|
|
103
106
|
if (config.player) return config.player
|
|
104
107
|
|
|
105
108
|
const players = ["paplay", "aplay", "afplay"]
|
|
@@ -306,10 +309,14 @@ export const BoopsPlugin: Plugin = async ({ client }) => {
|
|
|
306
309
|
|
|
307
310
|
return {
|
|
308
311
|
event: async ({ event }) => {
|
|
312
|
+
// Reload config on every event for instant updates (no restart needed!)
|
|
313
|
+
config = await loadConfig()
|
|
314
|
+
|
|
309
315
|
// Log session.idle events for debugging (helpful for users configuring filters)
|
|
310
316
|
if (event.type === "session.idle") {
|
|
311
317
|
await log(`session.idle event received`, {
|
|
312
|
-
properties: event
|
|
318
|
+
properties: event,
|
|
319
|
+
configuredSound: config.sounds["session.idle"]
|
|
313
320
|
})
|
|
314
321
|
}
|
|
315
322
|
|