- reject explicit ssh:// port 0 before connecting (Codex P2)
- keep a path-less ssh://host:port authority port out of selector peeling
- restore ResolveContext on ProtocolHandler.complete (symmetry with resolve/write)
- clarify search/read selector-parity docs + add read-side regression
- ssh handler complete() suggests the configured hosts; bare `read ssh://` resolves to an immutable host index (markdown links per host)
- thread a minimal cwd through the completion pipeline (provider basePath -> getInternalUrlSuggestions -> router.complete -> handler.complete) so project-scoped ssh.json hosts resolve like the cwd-aware bare-read path
- scoped to configured SSH-capability hosts; opaque ~/.ssh/config aliases stay usable at ssh://alias/path but are not enumerated
- local handler complete() signature updated to match (behavior preserved; the router never threaded context to it)
- `read ssh://host/dir` lists a remote directory one level deep; `ssh://host/` lists the remote root
- add statRemotePath + listRemoteDir; resolve reads first and classifies on error (directory -> one-level listing, dirs-first, dotfiles included)
- directory resources carry isDirectory + immutable and expose no sourcePath
- search refuses a virtual (no-sourcePath) directory resource instead of grepping the listing text
- writeRemoteFile refuses a directory destination and cleans up its temp on that path
- buildSshTarget rejects destinations beginning with "-" (SSH argument-injection / local RCE guard)
- gate ssh:// read/search/write at the exec approval tier; substring scan covers search's pre-expansion delimited paths and write's hashline-wrapped paths
- validate the entire materialized buffer as UTF-8 instead of only the first 8 KiB prefix
- write peels read selectors (raw/conflicts) so it targets the same file read does, and rejects line-range/malformed selectors instead of silently stripping them
- write to a uniquely named remote temp; document symlink-replacement on write as a v1 limit
- Updated `normalizeGeneratedTitle` to reconcile model-generated titles against the user's input instead of forcing title-case.
- Added logic to restore distinctive proper-noun casing (e.g., `TinyVMM`) and flatten model-generated camelCase artifacts (e.g., `dAemon`) that do not appear in the user's message.
- Ensured model-cased proper nouns that are not in the source message (e.g., `GitHub`) are preserved.
Fixed a non-deterministic gc-cli archive test: archive-me and keep-recent
shared ageDays:90, so their mtimes tied within a millisecond on fast CI and
the retainNewestGlobal:1 'keep newest' pick fell back to readdir order,
archiving the wrong session. Give keep-recent ageDays:60 (still cold-eligible,
unambiguously newer).
- Added instructions for writing sections as cohesive multi-line blocks when performing edit operations.
- Clarified that block operations require multi-line sections to avoid falling back to standard editing behavior.
- Added tree-sitter markdown support to resolve headings into full sections in `pi-ast`.
- Enabled block operations (`SWAP.BLK`, `DEL.BLK`, `INS.BLK.POST`) on markdown headings so they encompass the entire section, including nested deeper headings.
- Updated system prompt to guide agents in using structured markdown heading edits for plans.
- Fixed `plan-mode-guard` to correctly resolve local protocol options for subagents.
The createAgentSession default-role resolution ran before extension
factories registered their providers, so a default role pointing at an
extension-provided model (e.g. an openai-compat plugin's
posthog/claude-opus-4-8) returned undefined there. On a fresh launch
(no -c/--resume) the post-extension fallback went straight to
pickDefaultAvailableModel and replaced the user's configured default
with the first bundled provider default that had auth — commonly
openai/gpt-5.5 when OPENAI_API_KEY was set.
The fallback now retries resolveModelRoleValue against the
post-extension allowed-model set before pickDefaultAvailableModel, and
re-applies the role's explicit thinking selector / model host
preconnect.
Fixes#3569
Detected whether the OMP host already owns an inheritable Windows console before resolving stdio MCP spawn flags.
Skipped CREATE_NO_WINDOW for console-attached MCP wrapper chains so cmd.exe and PowerShell grandchildren reuse the existing terminal instead of allocating visible conhost windows.
Fixes#3567
- Removed multiple test files and cases that relied on brittle source string matching for validation.
- Updated project architecture documentation to explicitly prohibit source-grep style testing patterns.
- Eliminated legacy reproduction tests for issues that reached project maturity.
- Fixed stale `preserveData.snapcompact` frames leaking into context-full compaction after switching from `snapcompact` to `context-full` strategy, which inflated context usage and made sessions appear to compact prematurely.
- Added secret redaction for migrated snapcompact archive plaintext (`text`/`textHead`/`textTail`) during the snapcompact->context-full transition, while preserving opaque provider-replay state byte-identical.
- Added `archiveSourceText()` and `stripPreservedArchive()` utilities to snapcompact module for archive extraction and cleanup.
- Added a fallback from `hashline` to `replace` mode for Kimi-family models to resolve compatibility issues.
- Introduced `PI_STRICT_EDIT_MODE` environment variable to bypass automatic model-specific edit-mode fallbacks.
- Updated `getEditVariantForModel` to perform case-insensitive matching for model variant configurations.
- Added comprehensive unit tests for edit mode resolution and settings configuration.
Hidden slider means the operator made no choice; a singleton cycle built around the active plan model must not be pinned as executionModel, otherwise approval re-applies the plan model after #exitPlanMode restored the pre-plan one.
Added regression coverage for the plan-only role configuration.
Refs #3554
Same-model role with an explicit thinking suffix that differs from the pre-plan thinking now passes through applyRoleModel instead of being treated as an implicit match.
Added regression coverage for the sonnet:off vs pre-plan thinking-high case.
Refs #3554
Compared the selected approval tier against the model restored after plan mode instead of the active plan-mode tier.
Added regression coverage for keeping the active planning model selected on approval.
Fixes#3554
Allowed resource-server fallback OAuth discovery to accept authorization-server metadata whose issuer differs from the resource URL while keeping issuer matching for advertised auth-server candidates.
Added an Atlassian-shaped regression test so the fallback path no longer returns null.
Fixes#3551
The reload-cache regression fixture used ReturnType<typeof loadConfig>,
which violates the repository style rule banning ReturnType<>. Import and
use the explicit LspConfig type instead.
Fixes#3546
getConfig() in packages/coding-agent/src/lsp/index.ts cached the first
loadConfig() result per cwd permanently. If .omp/lsp.json, root markers,
or plugin LSP configs were added after the first LSP call, they stayed
invisible for the remainder of the process lifetime — even after the
user explicitly requested 'reload *' — because the reload handler
operated on the same stale config object retrieved at the top of
execute().
The reload-workspace branch now deletes the per-cwd cache entry and
re-runs getConfig() before iterating servers, so the refresh behaves as
the prompt documents. The cache is repopulated by the fresh read, so
subsequent calls still avoid the disk hit until the next 'reload *'.
Fixes#3546