- Added `resolveReleaseDist` and `shouldForceBinaryUpdate` to parse package manifests and gate major updates to binary releases.
- Implemented `updateViaShimTakeover` in `update-cli.ts` to seamlessly replace Windows script launchers with standalone binaries.
- Added comprehensive unit tests covering release distribution parsing, binary force updates, and script-shim takeover behavior.
- Define a centralized `USER_AGENT` constant in `@oh-my-pi/pi-utils` formatted as `omp/<version>`.
- Replace hardcoded and platform-specific user agent strings across AI providers, catalog scrapers, tools, and search providers with the unified `USER_AGENT`.
- Add unit tests for update-cli binary release distribution gating.
showHookCustom hardcoded the overlay geometry and never read
overlayOptions/onHandle, which regressed the v0.45.6 API (PR
badlogic/pi-mono#667). Forward overlayOptions to showOverlay (keeping the
full-cover defaults as fallback), invoke onHandle with the returned
OverlayHandle, widen the options type via a shared ExtensionCustomOptions,
and re-export OverlayHandle/OverlayOptions from the extension API.
Key hints resolved modifier tokens through a static, platform-agnostic label map with no `super` entry, so on macOS the shipped `super+v` paste default rendered 'Super+V' (no such key on a Mac) and `alt` always rendered 'Alt' instead of 'Option'. The static /hotkeys navigation rows were hardcoded with macOS 'Option'/'Cmd' names on every platform, so Linux/Windows users saw 'Cmd+Left'.
Modifier labels are now platform-aware: on darwin `alt` renders 'Option' and `super` renders 'Cmd'; every other platform keeps 'Alt'/'Super'. The platform is resolved through a single seam (setKeyHintPlatform/keyHintPlatform) mirroring the TUI's setKittyProtocolActive, keeping hint output deterministic in tests without mutating process.platform. The static /hotkeys rows use the same convention and drop the macOS-only Cmd line-start/end fragments (which map to no binding) off darwin.
Fixes#8235
The per-command non-interactive env hardcoded an unguarded CI=1, which clap parses as a strict boolean and rejects (breaking e.g. tauri android build). It also overrode the session env, so the documented PI_BASH_NO_CI opt-out never reached bash-tool commands.
buildNonInteractiveEnv now injects CI=true and strips CI when PI_BASH_NO_CI/CLAUDE_BASH_NO_CI is set, matching buildSpawnEnv in procmgr.ts.
Fixes#8229
Allowed advisor streams to treat Google STOP responses without visible content as successful silence while preserving the default retry behavior for interactive agents.
Added provider and advisor-path regressions covering retry counts, system instructions, and the advise declaration.
Fixes#8223
Cursor bash/grep frames wrote optional kwargs as present-undefined, and
tools.format gemini projectors dropped kCursorExecResolved so settled
calls ran twice.
Co-authored-by: Cursor <cursoragent@cursor.com>
handleUninstall dropped the parsed dryRun flag and unconditionally called
mktMgr.uninstallPlugin / manager.uninstall, so `omp plugin uninstall
<plugin> --dry-run` removed the plugin on both the marketplace and npm
routes. Propagate dryRun into handleUninstall and short-circuit before
both removal calls, reporting the resolved removal (with its source)
instead of mutating state.
Fixes#8178
- Expanded web search and fetching providers with robust parsing, authentication storage integration, and response validation.
- Added support for new configurations including SearXNG safesearch, Cloudflare AI Gateway endpoints, and dynamic Firecrawl base URLs.
- Implemented comprehensive test suites covering error handling, content filtering, and provider-specific response behaviors.
ensureRunnerScript() memoized the staged runner path in a module-level
RUNNER_SCRIPT_PATH and returned it on the warm path with no existence
check, defeating the cold path's own self-heal. If the tmpdir cache
(os.tmpdir()/omp-<lang>-runner) was cleared mid-session (e.g. a macOS
periodic clean_tmps sweep), the process kept handing out a path to a
deleted file and every later Python/Julia/Ruby kernel start failed to
spawn until restart.
Extract the three copy-pasted ensureRunnerScript implementations into a
single stageRunnerScript helper that re-checks fs.existsSync before
reusing the memoized path, so a swept runner is re-staged on the next
call. Route the Python, Julia, and Ruby kernels through it.
Fixes#8140
Why:
The module-global array memo strongly retains the most recently converted
transcript and output after its session is disposed.
Changes:
- Store exact-repeat and append-growth state in a WeakMap per input array.
- Preserve generation invalidation and per-message weak caching.
Evidence:
- Seven disposal runs collected both arrays after 50 forced-GC passes and
reduced median heap delta by 87.54%.
Refs #8119
Why:
RpcFrameEncoder serializes normal frames once for protocol routing and again
for output, while v2 snapshots serialize message payloads separately.
Changes:
- Feed the existing JSON into frame-size enforcement.
- Build v2 message snapshots from the serialized frame.
Evidence:
- End-to-end paired medians improved 10.72% for v1 and 15.72% for v2
across 25 pairs, with identical output hashes.
Refs #8118
Why:
SessionManager.open() parses the complete journal for its header and then
setSessionFile() parses the same journal again.
Changes:
- Reuse the entries already loaded by open() through a private setup path.
- Keep the public setSessionFile() contract unchanged.
Evidence:
- A 19.98 MB, 12,000-entry journal improved from 48.011 ms to
25.406 ms median across 15 runs with identical restored state.
Refs #8117
Why:
Local timeout cleanup removes pending state but leaves the language server
working on an abandoned request.
Changes:
- Send $/cancelRequest after an issued request reaches its client timeout.
- Preserve the existing timeout error and pending-request cleanup.
Evidence:
- The workspace-readiness regression observes cancellation for the dropped
status request before polling succeeds.
Refs #8116
Why:
The module-level idle interval remains referenced after every client shuts
down and keeps short-lived hosts alive.
Changes:
- Stop the idle checker before draining active and pending clients.
- Preserve explicit reconfiguration through setIdleTimeout().
Evidence:
- A child-process regression probe exits after shutdown with the checker
configured.
Refs #8115