Goal
- Make Hermes/Codex in VS Code emit a sound when a reply completes.
- Prefer patching the installed extension bundle only when no exposed setting exists.
Use when
- User says Hermes/Codex in VS Code should beep or play a sound after replying.
- Extension settings expose no audio-cue option for reply completion.
- You are on macOS and can use
afplay.
Prereqs
- Inspect the installed extension package first.
- Typical path:
~/.vscode/extensions/openai.chatgpt-<version>-darwin-arm64/
- Typical path:
- Confirm no direct configuration exists in
package.jsonfor reply-complete audio. - Search
out/extension.jsfordesktop-notification-show.
Key findings
- In the shipped Codex VS Code extension bundle,
desktop-notification-showmay be explicitly ignored:case\"desktop-notification-show\":case\"desktop-notification-hide\":break;
- Patching that branch restores sound only if the webview/runtime actually emits
desktop-notification-show. - Empirical finding: reply completion may not travel through
desktop-notification-showat all. - Empirical finding: a coarse
log-messagecompletion heuristic can fire at the wrong time and is not reliable for true reply-end semantics. - Better fallback patch point exists in the webview bundle reducer handling streamed thread events:
webview/assets/index-*.js- reducer branch:
case\turn/completed`inside the function that folds thread events into turn state (seen aroundZfe(...)` in current bundle)
- If extension-side notification patch is insufficient, prefer triggering audio directly from the webview on
turn/completed/ final assistant completion path instead of routing through ignored desktop notifications.
Patch recipe
- Backup target file.
cp out/extension.js out/extension.js.bak-hermes-beep
- Replace the ignore branch with a handler that:
- calls
vscode.window.showInformationMessage(...) - spawns
afplay /System/Library/Sounds/Glass.aiff
- calls
- Use a detached child process so the extension host does not block:
require("node:child_process").spawn("afplay", ["/System/Library/Sounds/Glass.aiff"], { detached: true, stdio: "ignore" }).unref()
- Validate syntax:
node --check <full path to out/extension.js>
- Tell user to run
Developer: Reload Window.
If no beep occurs at true reply completion
6. Do not trust a broad log-message heuristic as the final fix; it can beep at the wrong time.
7. Inspect webview/assets/index-*.js for the thread-event reducer that handles:
turn/completeditem/completeditem/agentMessage/delta
- Prefer patching the reducer branch for
turn/completedor the final assistant-message completion path to trigger audio locally in the webview.- Lowest-friction fallback:
window.parent.postMessage({ type: 'desktop-notification-show', title: 'Hermes', body: '回复完成' }, '*') - More robust fallback when parent routing is unreliable: call audio playback directly in the webview bundle, e.g.
new Audio(<data-uri-or-local-safe-source>).play().catch(() => {})
- Lowest-friction fallback:
- If using the webview path, also consider adding a tiny listener in
webview/index.htmlfordesktop-notification-showas a backup, but do not assume that listener alone fixes missing upstream events. - Validate syntax for patched JS bundle(s) and reload the VS Code window again.
Known-good replacement shape
case"desktop-notification-show":{
try{
let n=r?.title??"Hermes",o=r?.body??r?.message??"回复完成";
ke.window.showInformationMessage(`${n}: ${o}`);
require("node:child_process").spawn("afplay",["/System/Library/Sounds/Glass.aiff"],{detached:!0,stdio:"ignore"}).unref()
}catch(n){
Y().warning("[hermes-beep] desktop notification failed",{safe:{error:String(n)},sensitive:{}})
}
break
}
case"desktop-notification-hide":break;
Verification
node --checkexits 0.- Manual smoke test:
- reload VS Code window
- trigger a Hermes/Codex reply
- confirm toast + sound
- Optional direct audio test:
afplay /System/Library/Sounds/Glass.aiff
Pitfalls
- This edits installed extension output, not source.
- Extension updates overwrite the patch.
- Bundle is minified; patch exact unique string, not broad regex.
search_filesmay not show the minified branch cleanly after patch; rely on exact replace success +node --check.- On non-macOS systems, replace
afplaywith platform-appropriate audio command. desktop-notification-showrestoration alone may still produce no sound if reply completion never emits that message.- A
log-message-based hook is tempting but can fire before true reply completion. window.parent.postMessage(...)from the webview may also fail to surface if the host does not route arbitrary message types back into the extension handler; direct in-webview audio is the stronger fallback.
Rollback
- Restore backup:
cp out/extension.js.bak-hermes-beep out/extension.js
- Or reinstall/update the extension.
When not to use
- If the extension already exposes a supported reply-audio setting.
- If user only wants standard VS Code audio cues; then prefer settings over patching installed code.