- Added PDF member read syntax (`doc.pdf:<member>`) and trailing-colon listing.
- Added asset-read handling to serve extracted PDF images as inline image content.
- Added PDF image extraction caching keyed by size and mtime with marker files for retries.
- Added basename validation that rejects unknown/traversal-like PDF members and shows available names.
- Added `images.describeForTextModels` configuration defaulting to true for text models.
- Added `describeAttachedImagesForTextModel` to persist images and generate local:// descriptions.
- Added image-description notices to session flow with hidden typing and pre-user insertion.
- Added fallback behavior that returns notes when vision is unavailable or output is empty.
- `ProcessTerminal` now captures a per-instance `#headless` from `isTerminalHeadless()` at construction and re-reads it in `start()`; when set, `#safeWrite`, `start`, `stop`, `drainInput`, and `setProgress` short-circuit, so frame paints, `start()` probes (OSC 11 / DA1 / kitty), the progress keepalive, stdin raw mode, SIGWINCH, and teardown escapes no longer reach a real terminal during `bun test` (previously `#safeWrite` only skipped on `!isTTY`, so an interactive terminal leaked stray boxes and probe queries).
- Gated the `emergencyTerminalRestore()` blind-restore branch and `TerminalInfo.sendNotification` on the headless flag, and guarded `setTerminalTitle`/`pushTerminalTitle`/`popTerminalTitle` in `title-generator.ts`.
- Opted the terminal-contract suites (terminal-appearance, notifications, emergency-restore-altscreen, issue-2034 write gate, process-terminal-render-harness, render-stress-harness) back into real I/O with `setTerminalHeadless(false)`, restoring on teardown.
- Added `process-terminal-headless.test.ts` asserting zero writes under a forced TTY when headless and real frame/probe output after opt-out.
Route MuPDF WASM print/printErr warnings to logger.debug instead of console.error/the TUI (issue #2766). NOTE: duplicates #2768 for the same issue; merged as the more complete fix (ships an end-to-end regression test) - close#2768.
Installed the MuPDF WASM print hooks before markit-ai can import mupdf, preserving recoverable PDF warnings in the file logger instead of terminal stderr.\n\nAdded a regression test with a tagged PDF Screen annotation that previously reached console.error while conversion still succeeded.\n\nFixes #2766
Register tree-sitter-elisp in the shared AST language registry so
.el files infer the emacs-lisp grammar across blockRangeAt,
summarizeCode, astGrep/astEdit, and native aliases.
This fixes edit-tool block operations on top-level Emacs Lisp forms
instead of returning unsupported-language block errors.
- Add canonical emacs-lisp aliases and .el extension inference.
- Teach summaries to fold Lisp forms without grouping arbitrary lists.
- Map .el rendering and highlighting aliases through coding-agent/native.
- Cover defun, ERT, use-package, with-eval-after-load, pcase,
summary, astMatch, astEdit, and edit-tool insertion paths.
- Document the language and update package changelogs.
- Canonicalized assistant and thinking messages by trimming and collapsing dot text.
- Skipped rendering assistant and thinking blocks when canonicalized content was empty.
- Filtered ACP thinking notifications and session outputs to ignore placeholder content.
- Added canonicalizeMessage tests for undefined, blank, whitespace, and dot-only inputs.
The external editor flow (Ctrl+G, plan editor, /todo edit) warned 'No
editor configured' on Windows because getEditorCommand() returned
undefined whenever neither $VISUAL nor $EDITOR was set — the default
state for most Windows shells.
Fall back to 'notepad' on win32 after consulting $VISUAL/$EDITOR
(always present in %SystemRoot%\\System32) and trim env values so
accidentally padded strings still resolve. POSIX still returns
undefined so the warning continues to nudge users to configure an
editor.
Fixes#2604
- Added a new built-in `title` model role with `hidden` metadata and updated role definitions and schema.
- Updated title generation to resolve models in `title`, `commit`, then `smol` order and added test coverage for that precedence.
- Filtered hidden roles from selector badges and documented the new built-in role in model/settings docs.
- agent-loop: raise repetition-detection floor to 180 chars and clear thinking
replay anchors when collapsing a detected loop.
- providers/google: ignore empty text parts, retain terminal thoughtSignatures,
and stop function-call signatures clobbering the prior block.
- autolearn: capture goal-mode at the turn boundary; harden managed-skill writes
against hard-links/symlinks (O_NOFOLLOW + nlink); refuse minting managed skills
whose name an authored skill already claims.
- eager tasks: thread agentKind through the session so a custom top-level agentId
still gets always-mode delegation; split Eager Tasks prompt into hard vs soft.
- title-generator: race the online title model against a local tiny-model fallback.
- eager-todo: keep the soft reminder aligned with the todo init schema.
- mcp/stdio: keep close() detaching the read loop instead of awaiting it.
- stream loop: fix collapsing and tool-call thought-signature handling.
- Added unified `omp setup speech` flow with JSON/check modes and model picker.
- Added local STT pipeline with sherpa workers, recorder/download flow, and streaming inference.
- Added local TTS pipeline with `omp say`, backend selection, and streaming vocalization.
- Replaced legacy speech settings with unified `speech`/`speechgen` configuration keys.
- Updated OpenAI context promotion linking to resolve target models by parsed version and provider/API match instead of fixed bare ids.
- Scanned available siblings to select the plainest matching gpt-5.4 fallback so namespaced, dotted, and dated 5.5 variants promote correctly.
- Adjusted the TUI render stress shadow writer to ignore alternate-screen regions and replay only normal-screen bytes after exits.
Added OpenAI-compatible compat metadata for endpoints that allow tools but reject forced tool_choice. OpenCode Go kimi-k2.7-code now downgrades resolve-gate forcing to auto tool selection while preserving thinking-mode request state.\n\nFixes #2546
- Added new system prompts that ask models to emit titles inside `<title>` markers when forced tool calls are unavailable.
- Updated `generateTitleOnline` to use marker-based prompting and disable required `set_title` tool calls for models that do not support forced tool choice.
- Adjusted title parsing to extract the `<title>...</title>` value and fall back to stripped marker text when wrapping tags are incomplete.
- Validated queued toolChoice against active tools in agent and coding-agent sessions.
- Rejected queued forced choices with reason "unavailable" when selected tools were inactive.
- Dropped provider toolChoice payloads when requested function tools were not offered.
- Probed Tokio worker-thread support and fell back to current-thread runtime creation.
- Filtered dot-only or blank thinking blocks so they no longer render as assistant thought.
- Adjusted assistant-message and streaming-reveal logic to use visible-thinking helpers for consistency.
- Added getActiveModel support to session/tool interfaces for propagating active model objects.
- Added model capability helpers to flag WebP-unfriendly Ollama backends for image resize options.
- Updated image normalization and loading to auto-disable/reencode WebP when model constraints require it.
Fell back to the PowerShell clipboard bridge when the native Windows clipboard reader reports no image, preserving Ctrl+V image paste in PowerShell terminals.\n\nFixes #2429
Programmatic `git push` operations should not follow annotated tags configured by a user's `push.followTags = true`. This setting can lead to push failures if the remote rejects tag creation (e.g., in PR-head forks), even if the branch update itself is valid.
Adding `--no-follow-tags` explicitly overrides this user setting, ensuring only the specified refspec is pushed and preventing rejections.
- Dark themes: warm hues (0-120), Light themes: cool hues (180-300)
- Collision check against 17 major theme colors with 10° threshold,
clamped to the hue band so it never drifts into an unrelated range
- Hex values stored at construction instead of round-tripping through
ANSI escape parsing (removes #ansiToHex)
- WCAG AA contrast bisection on light surfaces
- Per-session uniqueness via name hash within the hue band
Self-review follow-up to 5cd9c01: the smart-paste fallback promotes
readTextFromClipboard's win32 branch to a primary path, and the legacy
execSync Get-Clipboard shell-out there had the same two defects the
review flagged on the WSL branch — it blocks the event loop and, worse,
reads through the console codepage so non-ASCII clipboard text arrives
mangled on non-UTF-8 Windows locales. Native win32 now shares
readTextViaPowerShell (UTF-8-forced, -Raw, async, CRLF-normalized).
Address review notes on #2248:
- readTextFromClipboard's WSL branch now mirrors readImageViaPowerShell
(Bun.spawn + kill timer sharing POWERSHELL_TIMEOUT_MS) instead of
execSync, so a cold powershell.exe start cannot block the TUI event
loop on the first smart-paste miss.
- The smart-paste text fallback routes through ui.getFocused() +
hasPasteText like the enhanced-paste text path, so the payload lands
in focused modal Input prompts instead of the hidden main editor
(#2127 contract). Covered by a new routing test.
app.clipboard.pasteImage dead-ended with a status message when the
clipboard held text, which made the chord useless on hosts that only
deliver that one keypress (VS Code's integrated terminal forwarding
Ctrl+V, Windows clipboard history via Win+V simulating Ctrl+V).
- handleImagePaste now pastes clipboard text through the editor's
paste semantics when no image is available; an empty clipboard
reports 'Clipboard is empty'.
- readTextFromClipboard reaches the Windows clipboard through host
PowerShell under WSL (mirroring readImageFromClipboard), with CRLF
normalization and UTF-8 output encoding.
- handleClipboardTextRawPaste's empty-clipboard status message moved
to the actual empty branch (was shown after successful pastes).
- Clipboard reads are constructor-injectable for tests.
Implements proposal 1 of #1628.
- add discovery of `TITLE_SYSTEM.md` and pass it through interactive startup context
- route custom title prompts to online and local tiny title generators via protocol
- update session-title docs and changelog with override behavior
- add tests for prompt discovery, forwarding, and fallback to bundled title prompts
The native arboard backend cannot retain X11 / Wayland selection ownership
after the calling process exits, and for short-lived napi calls it can drop
ownership before any consumer sees the selection — leaving the clipboard
empty even though set_text returned success. tmux + QTerminal made this
visible because OSC 52 is also dropped by libqtermwidget, so both backends
fail and the UI's 'Copied to clipboard' status reads as a lie.
utils/clipboard.ts now:
- Tries wl-copy / xclip / xsel before arboard on Linux. These CLIs fork
after reading stdin and serve the selection until another app claims it,
so the payload survives our process exit.
- Honors OMP_CLIPBOARD_COMMAND as a shell-string escape hatch (e.g.
`xclip -selection clipboard -in -silent`).
- Logs a single warning when every backend fails, so the silent-success
regression from #2075 cannot recur unnoticed.
Tests assert dispatch order: Linux+X11 prefers xclip, Wayland prefers
wl-copy, xclip→xsel fallback works, all-fail falls back to native,
macOS still goes straight to native, and OMP_CLIPBOARD_COMMAND wins
over the CLI chain.
Fixes#2075
Bare-repository worktrees resolve their git common dir to the bare repo
itself (for example /repos/foo.git), not to a directory literally named
.git. The first fix only collapsed non-bare linked worktrees, so bare
worktree layouts still fell back to each individual worktree root.
Return the shared commonDir for bare repositories from both
repo.primaryRoot and repo.primaryRootSync, update project-label docs,
and cover two worktrees attached to one bare repository in the
hindsight bank regression test.
Fixes#2232
Per-project-tagged scoping derived projectLabel() from
path.basename(cwd), so linked git worktrees of one repo landed retains
under distinct project:<basename> tags and recall (recallTagsMatch:
"any") missed cross-worktree memories.
- utils/git.ts: add sync sibling primaryRootSync to git.repo, walking
.git + commondir with sync file reads (no subprocess), returning null
outside a repo. Mirrors the async primaryRoot resolution.
- hindsight/bank.ts: projectLabel() resolves the primary checkout root
via primaryRootSync and basenames that; falls back to the cwd
basename when outside a repo. Sync only, so computeBankScope keeps
its sync API and the async cascade that sank #1218 is avoided.
- test/hindsight-bank.test.ts: regression block builds a real repo +
git worktree add fixture and asserts both produce the same
project:<primary> tag and per-project bank id, plus a non-repo
fallback case.
- CHANGELOG: Fixed entry under Unreleased.
Fixes#2232
- Added CredentialRankingStrategy scope hooks so providers can rank and block only the limits relevant to the requested model.
- Scoped Antigravity usage reports by model family: Gemini/Gemma use Google counters, Claude uses Anthropic counters, and GPT/OpenAI models use OpenAI counters.
- Added scoped backoff keys so a Gemini quota block no longer suppresses healthy Claude/OpenAI Antigravity sessions on the same OAuth credential.
- Threaded modelId through coding-agent API-key resolvers and usage-limit rotation paths.
- Added regression coverage proving a Google/Gemini exhaustion block still allows Claude selection on the same credential.
Fixes#2198
- Stored last-seen version in ~/.omp/agent/last-changelog-version so version bumps no longer dirty user configs.
- Migrated the legacy config.yml key into the marker, never clobbering a newer existing marker.
- Added read/write helpers and migration tests.