Releases: Nickdevcode/Ringly
v0.6.0 — Friendly release notes + /ringly-help
Highlights
/ringly-updatenow shows a friendly summary of what changed before asking for confirmation — read straight from the packaged CHANGELOG, rewritten in plain language for non-developers (≤10 lines, no file paths, no jargon).- The slash command now respects your configured language across every line it writes itself. Fixed the long-standing bug where
/ringly-updatemixed English step headers and prompts even whenpluginConfigs.ringly.options.languagewaspt-BR. The CLI now embeds the resolvedlanguagedirectly in the--checkJSON snapshot so the.mdhas a single source of truth. - New
/ringly-helpslash command runs the translatedringly helpand shows the full command list in the chat, with a clear "run these commands in your terminal, not here" warning. - New
ringly helpCLI subcommand replaces yargs' raw English--helpoutput with a translated overview. Works asringly help,ringly --help,ringly -h, andringlywith no args.
What's changed in detail
Added
- Friendly release-notes summary in
/ringly-update, read from the packagedCHANGELOG.md(no GitHub API call, no rate limits). /ringly-helpslash command.ringly helpCLI subcommand with full i18n.src/core/changelog.ts— Keep-a-Changelog parser, no new runtime dependency.
Changed
ringly update --checkJSON snapshot now includeslanguage(resolved server-side, neverauto) andnotes(structured{version, heading, groups: [{title, items}]}).- Interactive
ringly updatealso prints localized notes before the confirmation prompt — parity between terminal and slash command. /ringly-updaterewritten with explicit per-step language instructions tied tosnapshot.language.
Tests
- +30 new tests (133 → 163). Full coverage of the parser, the help renderer, and
buildNotesForrunning against the project's actual CHANGELOG entries.
Compatibility
- Nothing breaks. The 4 original fields of
ringly update --checkJSON stay identical (current,latest,hasUpdate,reachable) — the newlanguageandnotesfields are additive. - Hook bundle is untouched.
dist/hook.js/dist/hook.cjsstay at the same size — the changelog parser only loads from the CLI path, never from the hot path that runs on every notification event. - All 133 previous tests pass with no behaviour change.
How to update
npm install -g ringly@latestOr, inside Claude Code, run /ringly-update and try the new flow for yourself — it'll show you a summary of what's in this release before asking to install.
See the full CHANGELOG entry for the complete bilingual (pt-BR + en-US) details.
🤖 Generated with Claude Code
v0.5.2 — leaner hook bundle via read/write split
🇧🇷 Português
Mudado
- Bundle do hook ficou mais enxuto e separado da escrita de settings (
src/core/claudeSettings.ts,src/core/claudeSettingsWrite.ts,src/core/config.ts,src/core/configWrite.ts). Antes, o hook (caminho quente, executado em cadaNotification/Stop/SubagentStop) arrastava o módulo inteiro de manipulação de~/.claude/settings.json— inclusivechmodSync,copyFileSyncereaddirSyncdenode:fs, que são usados só pra escrever / fazer backup / podar backups antigos. Como o hook só lê config, esses imports nunca eram chamados, mas viajavam no bundle e geravam três warnings de tree-shake do Rollup a cadanpm run build. AgoraclaudeSettings.tsficou estritamente read-only (sóexistsSync+readFileSync+homedir+join) eclaudeSettingsWrite.tscarrega tudo que escreve. O mesmo princípio foi aplicado aconfig.ts(loadConfig+applyEnvOverrides) vs.configWrite.ts(saveConfig). Resultado:dist/hook.js/dist/hook.cjsnão puxam maischmodSync/copyFileSync/readdirSync, e os warnings somem do build. - Comportamento externo: nenhum. Quem usa o CLI (
ringly config,ringly init,ringly uninstall) ou o plugin no Claude Code não percebe diferença — toda mudança é interna ao layout dos módulossrc/core/. Os 133 testes existentes seguem passando sem alteração de comportamento.
Notas pra quem tá vindo da v0.5.1
- Nada quebra. A v0.5.1 (fix do
spawn EINVALno Windows) continua entregando exatamente o mesmo comportamento aqui. Esta release é puramente uma refatoração de bundle: hook mais limpo, separação read/write clara, sem custo nenhum pro usuário final.
🇺🇸 English
Changed
- Hook bundle is leaner and the settings-write surface is decoupled (
src/core/claudeSettings.ts,src/core/claudeSettingsWrite.ts,src/core/config.ts,src/core/configWrite.ts). Previously the hook (the hot path, executed on everyNotification/Stop/SubagentStop) dragged in the entire~/.claude/settings.jsonmanipulation module — includingchmodSync,copyFileSync, andreaddirSyncfromnode:fs, which only the writer needs (write, backup, prune old backups). Since the hook only reads config, those imports were never called but still shipped in the bundle and triggered three Rollup tree-shake warnings on everynpm run build. NowclaudeSettings.tsis strictly read-only (onlyexistsSync+readFileSync+homedir+join) andclaudeSettingsWrite.tscarries everything that writes. The same principle was applied toconfig.ts(loadConfig+applyEnvOverrides) vs.configWrite.ts(saveConfig). Outcome:dist/hook.js/dist/hook.cjsno longer pull inchmodSync/copyFileSync/readdirSync, and the build warnings are gone. - External behavior: none. CLI users (
ringly config,ringly init,ringly uninstall) and Claude Code plugin users see no difference — every change is internal to thesrc/core/module layout. All 133 existing tests pass with no behavior change.
Notes for v0.5.1 users
- Nothing breaks. v0.5.1 (the Windows
spawn EINVALfix) keeps delivering the same behavior here. This release is purely a bundle refactor: cleaner hook, clear read/write separation, zero cost to the end user.
📦 Install: npm install -g ringly@0.5.2
📦 Update from Claude Code: /ringly-update
📋 Full CHANGELOG: CHANGELOG.md
v0.5.1 — Spawn npm via shell on Node 20.12+ to unblock ringly update
v0.5.1 — Spawn npm via shell on Node 20.12+ to unblock ringly update on Windows
This patch fixes a regression on Windows where ringly update --yes (and therefore /ringly-update and the SessionStart auto-check) was throwing spawn EINVAL before npm could even start, leaving users with the raw errno and no way to update from inside Claude Code.
Fixed
-
ringly update --yeswas failing on Windows withspawn EINVALbefore npm even started (src/commands/update.ts). Root cause: since Node 20.12 / 21.7 / 22+ (CVE-2024-27980), Node refuses by design to spawn.bat/.cmdfiles directly on Windows withoutshell: true— exactly what we were doing withspawn("npm.cmd", [...], { shell: false }). The error fired before any localized CLI message could appear, so users only saw the rawspawn EINVALand had no idea what had broken.We now pass
shell: trueon Windows (lettingcmd.exeresolve the npm shim); macOS and Linux still useshell: false, behavior unchanged. Since the arguments are hardcoded literals (install -g ringly@latest), there is no command-injection surface. Anyone who was hitting this on Windows viaringly updateor/ringly-updatecan now update normally.
Changed
src/commands/update.tsnow exports a purebuildNpmInstallSpec(platform)helper that returns{ command, args, options }, deciding the shell per platform. This isolates the spawn decision and makes it unit-testable without mockingnode:child_process.runNpmInstallLateststays private and uses the spec.
Tests
- +4 new tests in
test/update.test.tscovering the regression: same command/args across platforms,shell: trueon Windows,shell: falseon macOS/Linux, andstdio/windowsHidepreserved. TheEINVALwas reproduced directly on Node v22.14.0 before the fix; the new path runs npm successfully.
Upgrade notes
- Nothing breaks. The fix is internal to the
ringly updatesubcommand /SessionStarthook //ringly-updateslash command. - macOS and Linux users notice no difference.
- Windows users on modern Node who were hitting
spawn EINVALcan now run/ringly-updatestraight from Claude Code, orringly updatefrom the terminal, without having to copy-pastenpm install -g ringly@latestthemselves.
Full changelog: v0.5.0...v0.5.1
v0.5.0 — Drop userConfig, CLI-only configuration
v0.5.0 — Drop userConfig, CLI-only configuration
This is a small but breaking release: it removes Ringly's userConfig block from plugin.json because the official Claude Code plugin-manager schema ships three UX issues we can't fix from the plugin side. Configuration is now exclusively CLI-driven through ringly config, hand-editing ~/.claude/settings.json, or re-running ringly init.
Breaking change
-
Removed
userConfigfromplugin/.claude-plugin/plugin.json. Up to v0.4.x, Claude Code exposed Ringly under/plugin→ Installed → Ringly → Configure with a native settings screen. That screen shipped three known issues that came from Claude Code's officialuserConfigschema, not from our plugin:- The
languagefield rendered as a free-text input — the schema has noenumsupport. A typo onpt-BR/en-USsilently fell back toauto. - On booleans,
Enteronly navigated between fields; onlySpaceactually toggled them. Multiple users reported "I unchecked it and it stayed on." - No atomic write, no
/reload-pluginsreminder.
Until Anthropic adds enum support to the schema and fixes the
Enterbehavior, we'd rather dropuserConfigentirely than pretend the UX was fine. Configuration is now CLI-only —ringly config(the recommended TUI), hand-editing~/.claude/settings.json, or re-runningringly init. The plugin still shows up under/plugin → Installed(hooks are still registered), but the Configure entry simply does not exist for Ringly anymore. Anyone with values already saved underpluginConfigs.ringly.optionsloses nothing: the dispatcher andringly configkeep reading and writing the exact same keys. Only the native plugin-manager UI is gone. - The
Changed
displayNameanddescriptioninplugin.jsonupdated to make it explicit that configuration goes throughringly config, not the plugin manager. Anyone browsing the marketplace sees it right in the description.- Final screen of
ringly config(TUIConfigDone) rewritten: the "You can also configure via/plugin→ Installed → Ringly → Configure" box was replaced with a "CLI-only configuration — Ringly does not use the plugin-manager screen. To change these settings later, runringly configagain." note. The yellow/reload-pluginsreminder is unchanged. ringly doctorhints that pointed at "open/pluginin Claude Code → Installed → Ringly → Configure" now point atringly configonly. The check itself is still called "Ringly settings in~/.claude/settings.json" and still validates the samepluginConfigs.ringly.optionskey — only the hint copy changed.pt-BR.jsonanden-US.jsonlocales gainedtui.config.cli_only_titleandtui.config.cli_only_body;tui.config.also_availableandtui.config.plugin_pathwere removed (no consumer remained after theConfigDonerewrite). Doctor hints (cli.doctor.check.plugin.notfound_hintandnooptions_hint) were rewritten to drop any mention of the plugin manager.
Docs
README.mdgained a "Why we don't use Claude Code's plugin manager" section (pt-BR and en-US) that explains the three problems above, links directly to the official plugin reference, and documents that the removal is intentional, not a bug. The "Three ways to configure" table became "How to configure (the only supported flow)" with three entries (ringly config, hand-edit,ringly initfor reinstall). The "How Ringly resolves the config at runtime" section was simplified from four layers to two (settings.json+ env-var overrides).plugin/README.mdsays the same thing, shorter, linking back to the main repo.CONTRIBUTING.mdgained an "Aboutplugin.jsonwith nouserConfig" section (pt-BR and en-US) so contributors don't try to reintroduceuserConfigwithout context. The note asks them to first confirm Anthropic has addedenumsupport before proposing the change.
Upgrade notes
- Nothing breaks.
ringly configkeeps working identically,ringly initkeeps working identically,~/.claude/settings.jsonkeeps being read identically. The only thing that changes is that the/plugin → Installed → Ringly → Configurescreen no longer exists. - If you configured anything via the plugin manager on v0.4.x, those values live in
pluginConfigs.ringly.optionsinsettings.jsonand are still honored — no migration needed. - If you want to reopen the configurator now that the screen is gone, run
ringly configin your terminal. You get the full TUI with arrow keys, space to toggle, and a visual language picker.
Full changelog: v0.4.0...v0.5.0
v0.4.0 — Guided self-update with /ringly-update and SessionStart auto-check
v0.4.0 — Guided self-update with /ringly-update and SessionStart auto-check
This release adds a complete self-update story to Ringly: a /ringly-update slash command that runs inside Claude Code, a once-a-day background npm check on session start that fires a native toast when a new version ships, and a new ringly update CLI subcommand that backs both flows.
Added
-
/ringly-updateslash command (plugin/commands/ringly-update.md). Runs inside Claude Code. Detects whether the npm CLI is installed, queries npm viaringly update --check, shows the version diff, asks for confirmation throughAskUserQuestion, runsringly update --yes, and reminds you to run/reload-plugins. Theallowed-toolsfield is scoped toringly:*andnpm install -g ringly:*— the command never touches user files directly; everything goes through the CLI. -
SessionStarthook (plugin/hooks/hooks.json+src/commands/updateCheckHook.ts). Once a day, at session start, the plugin queries npm in the background. When a newer version is available, it dispatches the same native toast the existing notification hooks use — title "Ringly", body localized in pt-BR/en-US, telling you to run/ringly-update. Throttle state is persisted at${CLAUDE_PLUGIN_DATA}/last-update-check.json. Opt-out viacheck_updates: falseskips all I/O before the throttle file is even read. The hook is fail-silent: any failure logs and exits 0 so it never delays or blocks session start. -
ringly updateCLI subcommand (src/commands/update.ts). Works outside of Claude Code too. Three modes:ringly update— interactive, with a visual box,s/y/Nconfirmation, and localized strings.ringly update --check— just prints{current, latest, hasUpdate, reachable}JSON for scripts and for/ringly-updateconsumption.ringly update --yes— skip confirmation and install directly.
Detects
EBUSY/EPERM/access is deniedin thenpm installstderr and swaps the message for a "close Claude Code and retry" hint on Windows. -
check_updates: booleanoption added toplugin/.claude-plugin/plugin.json#userConfig(defaulttrue), with the matching key wired throughclaudeSettings,RinglyConfig,applyEnvOverrides(CLAUDE_PLUGIN_OPTION_CHECK_UPDATES), and thedispatch.mjsDEFAULT_OPTIONS/eventEnabledswitch. -
src/core/updateCheck.ts— isolated, dependency-free module with:checkForUpdate(Node 20+fetchwith a 3 sAbortControllertimeout).compareSemver(prerelease-aware).shouldCheckUpdate/recordCheck/readLastCheckRecord(24 h throttle, atomic write of timestamp).
-
src/core/ownVersion.ts— walk-up helper that finds thepackage.jsonwithname: "ringly"so bothupdate.tsandupdateCheckHook.tsresolve the current version correctly when running from source, from thedist/bundle, or from a globally-installed npm prefix.
Changed
plugin/hooks/dispatch.mjswhitelistsSessionStartand treats it as a separate path: tries the Node module / CLI binary delegations like the other events, but does not fall back to the embedded toast — the event is a check, not a direct notification, so without the CLI there's nothing useful to fire.src/cli.tsinternalhooksubcommand now acceptsSessionStartas a positional event, used by the dispatcher's CLI-binary fallback path.RinglyConfiggainedcheckUpdates: boolean, propagated throughtypes.ts,config.ts(DEFAULT_CONFIG+applyEnvOverrides), andclaudeSettings.ts(read/write underpluginConfigs.ringly.options.check_updates).
Tests
- +35 new tests (94 → 129).
test/updateCheck.test.tscovers 30 scenarios: semver comparison (equal/greater/lower/prerelease), input validation (bad package names and bad semver),shouldCheckUpdateat every boundary,recordCheck/readLastCheckRecordround-trip and corrupt JSON,checkForUpdateagainst 200/404/network throw/invalid JSON/AbortControllertimeout, and a custom registry URL.test/updateCheckHook.test.tscovers 5 hook-level scenarios: opt-out viaCLAUDE_PLUGIN_OPTION_CHECK_UPDATES, throttle within 24 h, no-update branch, unreachable-network branch, and tolerance to a malformedlast-update-check.json.
Docs
- README "Updating" section rewritten in pt-BR and en-US covering
/ringly-update, the auto-check, the manual update path, and how to disable the check. New CLI commands documented.check_updatesadded to the options table. "How it works" updated to includeSessionStart. plugin/README.mdlists all 5 hooks (includingSessionStart) and describes the new slash command +check_updatesoption.CONTRIBUTING.mdupdated: test count bumped from 94 to 129, theALLOWED_EVENTSwhitelist now listsSessionStartwith its special-case behavior, and the project layout includescommands/ringly-update.md,core/ownVersion.ts,core/updateCheck.ts,commands/update.ts, andcommands/updateCheckHook.ts.
Upgrade notes
- After upgrading, run
/reload-pluginsinside Claude Code so the newSessionStarthook registers. - If you don't want the auto-check, set
check_updates: falsein~/.claude/settings.jsonunderpluginConfigs.ringly.options(or runringly configand toggle it). - The auto-check is fully fail-silent and bounded by a 24 h throttle, so it will never delay session start or hammer the npm registry.
Full changelog: v0.3.0...v0.4.0
v0.3.0 — Security hardening, legacy removal, atomic writes
v0.3.0 — Security hardening, legacy removal, atomic writes
This is a major release focused on security, robustness, and removing dead weight. It deletes the entire legacy compatibility system, makes the settings.json writes atomic and crash-safe, validates and truncates every untrusted input, and aligns versions across package.json and plugin.json after a previous drift.
Breaking changes
-
Removed the entire legacy system. The
src/core/legacy.tsmodule, theringly init --migrate-legacyandringly uninstall --legacyflags, thedoctorlegacy check, and the migration section in the README were deleted. This system existed to detect and disable pre-Ringly PowerShell hooks at~/.claude/hooks/notify-toast.ps1that could fire duplicate notifications. Since Ringly has been stable across several versions, the compatibility bridge became dead weight. Migration: if you still have legacy PowerShell hooks in~/.claude/hooks/, remove them manually before installing Ringly 0.3.0 — or runringly uninstall --legacyon 0.2.x before upgrading. -
Removed the
~/.config/ringly/config.json(env-paths) fallback. Config now lives only in~/.claude/settings.jsonunderpluginConfigs.ringly.options. Pre-0.2.x installs need to runringly initonce to migrate; 0.2.x+ installs already usesettings.jsonas the primary source and don't need to do anything. Bundle shrunk ~14 KB oncli.jsand ~3 KB onhook.jsas a result. -
ringly uninstallnow removes thepluginConfigs.ringlykey fromsettings.json(with atomic write + backup) instead of deleting the oldconfig.json. The--keep-configflag still exists to preserve your settings.
Security & robustness
- Atomic write of
~/.claude/settings.json(src/core/atomicWrite.ts). Previously,writeFileSyncwrote directly to the final file, and a race betweenringly config(TUI) and a hook fired by Claude Code could corrupt the file or lose changes. Writes now go to a temp file (settings.json.tmp.<pid>.<rand>) and only get renamed to the final file via an atomic rename (atomic on NTFS since Windows Vista; guaranteed by POSIX). On failure the temp file is removed — no partial files. - Lightweight payload validation (
src/core/payloadGuards.ts). JSON from Claude Code's stdin now passes throughcoerceClaudeHookPayload, which accepts only whitelistedhook_event_namevalues, truncatesmessage/agent_type/error_type/errorat 500 chars, truncatescwd/transcript_pathat 1024 chars, and drops unknown fields. No new dependency; addresses DoS-via-large-payload risk and adds defense in depth. - Stdin limit reduced from 10 MB to 256 KB in both the CLI (
src/core/stdin.ts) and the plugin dispatcher (plugin/hooks/dispatch.mjs). Real Claude Code payloads are typically <2 KB; 256 KB is already a generous defense. - Validation of
appIdloaded from config (src/core/config.ts). Only[A-Za-z0-9._-]{1,128}is accepted; invalid values fall back toClaude.Code.CLIwith a warning. Defense in depth — PowerShell escaping was already safe, but explicit validation prevents surprises if a third-party plugin writes garbage to the field. settings.jsonset to mode0600on Linux/macOS after each write. Since the file may contain tokens from other plugins, restricting reads to the owner is the right posture. Windows still inherits~/.claudeACLs.- Automatic GC of old backups. Previously, each
ringly configleft a permanentsettings.json.ringly-bak.<timestamp>. Backups older than 7 days are now removed automatically before creating a new one. - Log rotation at 5 MB (
src/core/logger.ts). Theringly.logwas growing unbounded in debug mode. Files over 5 MB are now rotated toringly.log.1(overwriting the previous rotation). The size check is throttled to once per minute to keep the hot path cheap.
Behavior
- Locale detection reordered: precedence is now
CLAUDE_PLUGIN_OPTION_LANGUAGE→Intl.DateTimeFormat→LANG/LC_*→ fallbacken-US. PreviouslyLANGcame beforeIntl, which gave wrong results for BR users running Claude Code from WSL/Git Bash withLANG=C.UTF-8. - macOS/Linux toast now warns explicitly that it is not implemented instead of failing silently. The toast channel's
isAvailable()returnstruefor windows/macos/linux, and the macOS/Linux stubs print a clear stderr message (once per process) pointing to the GitHub tracker. Previously,ringly teston macOS was a silent no-op.
Build & packaging
- Smaller npm tarball.
package.json#filesnow only includesbin/,dist/,plugin/,scripts/,README.md,LICENSE,CHANGELOG.md. Thesrc/,tsup.config.ts, andtsconfig.jsonentries were removed — end users don't need source nor build config (that path is only used vianpm install -g <github-shorthand>, already covered byscripts/prepare.js). Final tarball: ~242 KB / 22 files. sideEffects: falseenabled inpackage.jsonso consumers importingringly/hookget real tree-shaking.- Versions synced:
package.jsonandplugin/.claude-plugin/plugin.jsonare both at0.3.0now. Previously there was a mismatch (package.json@0.2.4vsplugin.json@0.2.1, last published tagv0.2.3). npm run lint/lint:fix/formatscripts now also coverplugin/hooks/(matchingbiome.jsonincludes).
CI / Release
ci.ymlnow runsnpm run lint(coversplugin/hooks/) plus smoke execution ofdist/cli.js --version,--help, and a sample hook onubuntu-latest. Catches top-level runtime / circular import errors before publish.release.ymlverifies that the git tag matches bothpackage.json#versionandplugin.json#versionbefore publishing to npm. Blocks silent inconsistencies.- Dispatcher timeout standardized to 12 s (was 10 s), giving margin over the 8 s PowerShell timeout to avoid killing the child Node before the toast finishes.
Tests
- +12 new tests across new files:
payloadGuards,stdin,notifier,channels,runHook. Critical-path coverage is now >80% forsrc/core/andsrc/channels/. - Additional
claudeSettingstests verify the atomic write leaves no orphan.tmp.*files and that backup GC respects the 7-day window. detectSystemLanguagetests validate the newIntl-first fallback order with mockedIntl.DateTimeFormat.
Coverage thresholds were adjusted in vitest.config.ts to 65% on branches (others at 70%), with src/platform/** and integration-heavy commands (init/config/doctor/test/uninstall) excluded from measurement since they exercise PowerShell/AUMID/child_process flows.
Also includes the v0.2.4 Windows toast fix
If you skipped v0.2.4 (the retroactively-tagged Windows fix), the same change is included here: the PowerShell WinRT COM adapter bug (PowerShell#9816) that silently dropped toasts on Windows 11 / PowerShell 5.1 is fixed by reading $notifier.Setting.value__ directly.
Upgrade notes
- After upgrading, run
/reload-pluginsinside Claude Code so the hooks pick up the new dispatcher. - If you had legacy PowerShell hooks at
~/.claude/hooks/notify-toast.ps1, remove them by hand or downgrade to 0.2.x, runringly uninstall --legacy, then upgrade to 0.3.0.
Full changelog: v0.2.3...v0.3.0
v0.2.4 — Bypass WinRT COM adapter bug breaking toast notifications
v0.2.4 — Bypass WinRT COM adapter bug breaking toast notifications
🏷️ Note: this tag was created retroactively from commit
9f2da8eto align the GitHub release history with the[0.2.4]entry that already existed inCHANGELOG.md. The fix below is also included in v0.3.0 — if you're on v0.2.x and just want this specific fix without the v0.3.0 breaking changes (legacy system removal), you can pin toringly@0.2.4.
This release fixes a critical Windows 11 / PowerShell 5.1 bug that caused toast notifications to be silently dropped, even when everything else looked correctly configured.
Fixed
-
Silently blocked notifications on Windows 11 / PowerShell 5.1. On several setups — especially Claude Code installed via global npm with the AUMID registered through a shortcut — the toast never appeared visually; only a short
beepplayed. Root cause: a known PowerShell bug (PowerShell#9816) where WinRT objects implementIInspectablebut notIDispatch. As a result,$notifier.Settingreturned a mis-typed enum when compared with[NotificationSetting]::Enabledor concatenated into a string. The comparison silently produced a false-positiveBLOCKED:classification with an empty reason (visible in logs asBLOCKED:with nothing after the colon), abortingShow()before the toast could fire.The check now reads
$notifier.Setting.value__— the intrinsic backing field of any .NET enum, accessed directly without going through the broken COM adapter — and compares against integer0(Enabled). If the read fails for any reason, the code falls through toShow()rather than block; any real error surfaces via thecatchwith a meaningful message instead of a phantom block. Non-zero values are mapped to readable reasons (DisabledForApplication,DisabledForUser,DisabledByGroupPolicy,DisabledByManifest). -
Removed the
[Console]::Beep(800, 200)fallback on the blocked path. That short beep was being emitted whenever the check false-positived and misled users into thinking the notification had actually arrived — when in fact it was just the beep. When the toast is genuinely blocked by system configuration, the CLI now returnsBLOCKED:with a readable reason and emits no sound.
Tests
- +14 new tests in
test/psTemplates.test.tscovering the new robust check, the reason mapping, the absence of the misleading beep, and single-quote escaping in AUMID, XML, and shortcut path.
Upgrade notes
- If you've been seeing the "short beep but no toast" symptom on Windows 11, upgrade to v0.2.4 (or v0.3.0+). The fix is purely platform-level — no config or migration needed.
- If you want the modernized v0.3.0 (security hardening, atomic writes, legacy removal) and not just this fix, jump straight to v0.3.0.
Full changelog: v0.2.3...v0.2.4
v0.2.3 — Version bump
v0.2.3 — Version bump
Maintenance release. Only package.json and package-lock.json were touched to bump the version to 0.2.3 so the next published artifact lines up cleanly with the npm tag.
Changed
- Version bump to
0.2.3(db32ed4) — package.json and package-lock.json updated. No code or behavior changes since v0.2.2.
Upgrade notes
- This is a version-alignment release. If you're already on v0.2.2 there's no functional reason to upgrade unless you want your installed CLI's
--versionoutput to read0.2.3.
Full changelog: v0.2.2...v0.2.3
v0.2.2 — Install flow documentation fix
v0.2.2 — Install flow documentation fix
This is a docs-only patch that rewrites the install instructions in both README.md and plugin/README.md to match the actual install flow more accurately. No code changes.
Fixed
fix: Fixed install flow(cb66df6) — README andplugin/README.mdhad outdated steps that didn't match the realringly init+/plugin marketplace addflow. Rewrote the sections so that someone discovering Ringly for the first time can follow the steps end-to-end without hitting dead ends. 151 lines changed inREADME.mdand 14 inplugin/README.md.
Upgrade notes
- No runtime changes; safe to skip if you're already on v0.2.1 and don't need the updated docs.
Full changelog: v0.2.1...v0.2.2
v0.2.1 — Hooks read settings.json directly + full TUI/CLI i18n
v0.2.1 — Hooks read settings.json directly + full TUI/CLI i18n
This release fixes a silent-failure bug that affected every previous version: the hook dispatcher was relying on CLAUDE_PLUGIN_OPTION_* environment variables that Claude Code does not export to hooks, so every user's config — language, event toggles, sound — was being silently ignored at runtime. It also lands full internationalization across the TUI and CLI.
Breaking changes
- Hooks now read
~/.claude/settings.jsondirectly. In every previous release,dispatch.mjsdepended onCLAUDE_PLUGIN_OPTION_*environment variables that Claude Code does not actually export to hooks. The user's choices configured through the plugin manager were silently ignored, and the fallback always derived the language from the OSLANG. This is fixed: the dispatcher readssettings.jsonon every hook invocation and applies the language, event, and sound filters before any dispatch.
Fixed
- Full TUI and CLI internationalization. Strings across the TUI (Welcome, LanguagePicker, HookPicker, SoundDebugPicker, AumidRegister, Done, ConfigDone) and the non-interactive commands (
doctor,uninstall,test,init --non-interactive) were hardcoded in English. Now the entire interface respects the chosen language (pt-BR or en-US). Duringringly initthe TUI always starts in English — a deliberate design choice so every user gets a predictable starting point — and switches in real time the moment the user picks a language. Non-interactive commands honor the saved language. - Event filter now respected on every path. Previously, disabling
events_stopfrom the TUI/plugin manager didn't stopdispatch.mjsfrom firing the embedded fallback — only the "rich" Node CLI path filtered. The filter now runs before any dispatch, on every path. sound: falsenow silences the embedded fallback. The toast XML now uses<audio silent="true"/>when the user disables sound viasettings.json. Before, sound played anyway.- Windows
EINVALspawn fix intryCliBinary:.cmd/.batfiles now run withshell: true, letting the rich CLI path actually work on Windows. Before, it always fell back to embedded. tryNodeModulenow also triesnpm root -gas a second resolution strategy, soringly/hookis found even when the plugin lives in~/.claude/plugins/cache/(which has nonode_modules).- CLI
loadConfig()now prefers~/.claude/settings.jsonover the legacy env-pathsconfig.json. The localconfig.jsonis still read as a fallback for pre-0.2.x installs and is still written (alongsidesettings.json) for compatibility. It will be removed in a future release. ringly testwithout--langnow uses the user's actual config (fromsettings.json), instead of always falling back to internal defaults.
Docs
- README and CHANGELOG corrected the runtime-resolution docs (env vars were never the real source) and added the recommendation to use
ringly configfor the best UX, since the plugin manager schema does not supportenumand free-text input made typos silently fall back toauto.
Upgrade notes
- After upgrading, run
/reload-pluginsinside Claude Code so the hooks pick up the corrected dispatcher. - If you had language or event toggles configured through the plugin manager on v0.2.0 and they "didn't seem to work" — they really weren't working. They start working on v0.2.1 without any migration needed; the values were saved in
settings.jsoncorrectly all along, just not being read at runtime.
Full changelog: v0.2.0...v0.2.1