- Introduce `@oh-my-pi/omptype` as a new ArkType-compatible schema validation package featuring a lazy JIT runtime, JSON Schema emission, and compatibility adapters.
- Replace `arktype` across workspace packages and test utilities with `@oh-my-pi/omptype`.
- Add benchmark suites, tests, and documentation for the new validation engine and adapters.
- Update workspace build, test runner, and release configurations to include the new package.
Root cause of the reported "edit tool silently reformats the whole
file" corruption: fs/write_text_file has no verbatim guarantee. When
an ACP client (e.g. Zed with format_on_save: on) reformats a buffer
on save, routeWriteThroughBridge reported the pre-write content as
successfully written, and Patcher.commit keyed the returned snapshot
tag on that same pre-write text instead of what actually landed on
disk. The next edit anchored on that tag then resolved hunks against
a baseline the file had already drifted away from, which is what
produced whole-file "corruption" from single-line hunks -- reproduced
live in this session against real Swift/JSON/TypeScript files with
Zed as the ACP client.
- routeWriteThroughBridge reads the file back after the bridge write
and returns the verified content plus a drift flag (best-effort:
ACP defines no ordering between the client acking the write and its
own async format-on-save settling, so this degrades gracefully to
the old stale-tag-on-next-read failure mode, never to corruption).
- HashlineFilesystem.writeText propagates that verified content in
view-space (the same space readText returns -- e.g. a notebook's
editable cell text, not its raw JSON), not storage-space, so tag
validation on the next edit compares like with like.
- Patcher.commit keys fileHash/header/snapshot on the verified
post-write content (normalized, so BOM/line-ending restoration never
produces a false "drift") when it diverges from what was sent, and
appends a warning naming the drift -- but deliberately leaves the
returned `after` (and therefore the model-visible diff) scoped to
the intended hunk. Diffing against the full drifted file would
balloon the tool response to span every reformatted line (measured
~6.8x inflation on a 245-line file with one touched line); the
warning is the correct O(1) channel for "your editor reformatted
this," not an O(file-size) diff.
- write.ts keys its own snapshot header on the verified bridge content
too (no diff-size concern there since write always replaces the
whole file).
Caught via code review (dispatched against the first pass of this
fix): a naive "just use the verified content everywhere" fix broke
.ipynb editing outright (write-space vs read-space content mismatch,
tag invalid on every notebook edit) and would have inflated every
drifted edit response by ~6.8x. Both are now covered by regression
tests that fail against the pre-fix code and pass against this one.
(cherry picked from commit 35ab80e43be5800b2f48728e4400eb9fd7f7f7d2)
The guard now probes the full target before refusing, so an existing file
named like a selector list stays writable. Say so in the CHANGELOG entry
and the readSelectorListMisfire doc comment.
Probe the full target with probeLiteralPathExists before classifying it as a
mis-dispatched read-selector list, matching the single-selector guard, so an
existing POSIX file like 'report:1-2;archive:3-4' can still be overwritten.
- Replaced the `XdevRegistry` class with the `XdevState` interface and pure helper functions across core and session tools.
- Updated session configurations, tool execution, and renderers to utilize canonical tool map initialization and sharing.
- Adapted unit tests and mocks to use `XdevState` and associated helper functions for permission and dispatch verification.
The read-selector-misfire guard (#6123/#6387) short-circuited whenever
`content` was non-empty, so a semicolon-joined list of read selectors
(`a.txt:1-2;b/c.txt:3-4`) passed as a write path with content fell through
to ordinary filesystem creation and silently built a nested directory tree
in the workspace. `read` accepts no such list, so this shape is always a
mis-dispatched multi-file read.
Refuse any target that splits on `;` into 2+ segments each carrying its own
read selector, regardless of `content` — the non-empty-content escape hatch
covers a lone selector-shaped filename, never a `;`-list.
Fixes#6809
Passed session-scoped settings through Edit and Write generated-file checks and fell back to schema defaults when no global singleton exists.
Guarded inline image sizing against an uninitialized global settings proxy and added isolated-session regression coverage.
Fixes#6549
Applied the read-selector misfire check to archive members after loading
the archive entry map and before mutation. Missing empty selector-shaped
members now fail closed, while existing literal members remain writable.
Added regression coverage proving rejected writes leave archives unchanged.
A read-only step that mis-dispatches read as write passes the full read
expression (src/foo.tsx:1-260:raw) as the target. Because a literal colon
filename is legal on POSIX (#4618), write resolved it to filesystem creation
and reported success, leaving a stray zero-byte file the model could not
recover from - the local analogue of the xd:// near-miss guard (#6123).
assertNotReadSelectorMisfire now fails closed when the tail parses as a
read-tool selector, the literal target is missing, and content is empty,
pointing at the equivalent read(...). Non-empty content stays the escape
hatch and existing literal colon filenames remain writable.
Fixes#6387
- Exempted the handler-less conflict:// scheme from the URI-like guard so parseConflictUri still splices registered blocks.
- Extended the near-miss regression to assert conflict://1 reaches the resolver.
Fixes#6123
- Blocked malformed and unregistered URI-like paths before filesystem resolution.
- Suggested canonical xd:// spelling while preserving explicitly escaped local paths.
- Added regression coverage for xdt://, xd:/, and xd/ near misses.
Fixes#6123
Schema-invalid JSON objects can reach mounted approval functions before xdev dispatch validates their arguments. Fall back to the exec tier when an approval function throws, preserving fail-closed prompting and allowing dispatch to surface its normal schema error.
Added regression coverage for ast_edit payloads containing null paths.
Fixes#5727
The write approval gate discarded a mounted tool's function-valued
approval and never decoded the device JSON payload, defaulting the tier
to exec. Read/write xd:// operations then prompted in non-yolo modes
that permit them.
Now decode valid object payloads and resolve the mounted tool's normal
approval decision via resolveToolTier; malformed JSON, non-object
payloads, and unknown devices still fall back to exec and prompt.
Fixes#5727
- Added the `xd://` virtual device protocol (`internal-urls/xd-protocol.ts`, `tools/xdev.ts`): tools declaring `loadMode: "discoverable"` are unmounted from the request tools array and driven via `read xd://` (list/docs+schema) and `write xd://<tool>` (execute), gated by the `tools.xdev` setting (default on) and inlined into the system prompt.
- Merged the `irc`, `job`, and `launch` tools into a single `hub` tool (`tools/hub/`, `async/job-manager.ts`): messaging keeps `send`/`inbox`/`list`, job control maps to `wait`/`cancel`/`jobs`, process supervision keeps `start`/`logs`/`stop`/`restart`/`describe` with `ps`, and the unified `wait` races background jobs against peer messages; SDK `IrcTool`/`JobTool`/`LaunchTool` are replaced by `HubTool`.
- Removed the hidden `resolve` tool in favor of the `xd://resolve`/`xd://reject`/`xd://propose` resolution devices, auto-including `write` whenever a deferrable tool or plan mode is present.
- Removed the BM25 tool-discovery system: the `search_tool_bm25` tool, the `tool-discovery` module, the `tools.discoveryMode`/`mcp.discoveryMode`/`mcp.discoveryDefaultServers`/`tools.essentialOverride` settings, per-tool MCP selection, and the `mcp_tool_selection` message type.
- Unified tool presentation on `ToolLoadMode` (`essential`|`discoverable`), replacing the custom-tool `xdev?: boolean` opt-out; custom, extension, MCP, RPC host, image-generation, and TTS tools now default to `discoverable`, and added a `satisfies` predicate to `SoftToolRequirement`.
- Removed the standalone `ssh` command tool and `ssh/ssh-executor` (the `ssh://` read/write/search protocol stays), and made `--tools` address hidden built-ins.
- Updated collab-web to render `xd://` dispatches and `hub` op families, dropped the `search_tool_bm25`/`ssh`/`report-finding` renderers, refreshed tool docs and prompts, and migrated the affected tests and changelogs.
- Added `conflict://*` support to the `write` tool, allowing resolution of multiple conflicts in a single call using per-id directives.
- Implemented `parseBulkDirectives` to interpret `ID: @side` mappings from the raw input content.
- Enabled partial bulk resolution where unlisted conflict IDs remain registered for subsequent operations.
- Updated conflict documentation and tool summaries to reflect the new bulk resolution capability.
- Implemented logic to automatically detect and trim redundant lines duplicating adjacent file content within conflict markers.
- Added delimiter balancing and boundary tracking to ensure accurate removal of echoed text while preserving EOL formatting.
- Updated user feedback to report the number of trimmed echo lines during write and conflict resolution operations.
- Expanded test coverage to include multi-line echo scenarios and integration validation of the repair process.
- Offloaded slow LSP diagnostics to a deferred channel in the `write` tool to prevent blocking agent execution for the full 3-second poll window.
- Abstracted deferred diagnostic logic into a reusable `DeferredDiagnostics` class to standardize tracking and deduplication across tools.
- Updated `WriteTool` to support `beginDeferredDiagnosticsForPath` callbacks, surfacing diagnostics as an aside instead of stalling the tool result.
- Added a regression test validating that `write` completes immediately while diagnostics arrive asynchronously.
Blocked write tool filesystem fallback for read-only internal URL schemes so memory:// targets cannot be materialized as project-relative paths.
Added a regression test covering memory://root/memory_summary.md writes and the leaked memory:/root path.
Fixes#5075
The first-result viewport-repaint gate assumed only streamed
__partialJson placeholder shapes (SSH) could re-anchor; the write
renderer's collapsed pending preview paints a tail window from decoded
content, so its first partial result re-anchored to the top of the file
and left the committed tail rows stale above the new frame.
Resolve forceFirstResultViewportRepaint per renderer as a boolean or an
(args, options) predicate evaluated at paint time: write opts in when a
collapsed preview outgrew the streaming tail window, SSH stays scoped to
the streamed-placeholder shape it always covered.
Adopted from PR #4478 (roboomp) with an allocation-free line-count scan
and terminal-buffer regression coverage.
Fixes#4477
Validated path-like renderer inputs before calling path helpers so provider-supplied arrays or objects cannot crash TUI rendering before schema validation reports the bad tool call.
Added renderer regression coverage for read, write, and edit call/result components with array and object path arguments.
Fixes#4525
Bridge-backed writes now respect tool timeout/cancel: routeWriteThroughBridge takes an optional AbortSignal and forwards it to notifyWorkspaceWatchedFiles, so a wedged LSP server no longer hangs the bridge path.
Updated write, replace, patch, and hashline callers to pass the tool signal.
Refs #4459
Emitted partial write-tool updates before filesystem, archive, SQLite, internal URL, and conflict writes so the TUI can render execution-phase progress instead of waiting for the final result.
Updated the write renderer to keep partial results pending, show the progress snapshot, and suppress diagnostics until the final result.
Fixes#3960
- 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
- Promoted `write` and `find` tools to `essential` status to ensure they are always available regardless of discovery mode.
- Updated `DEFAULT_ESSENTIAL_TOOL_NAMES` to include these tools by default.
- Updated documentation and tests to reflect the change in default essential tool availability.
Fixes#3165
- Remove the static "pending" hourglass icon from edit and write tool headers to reduce visual noise.
- Update multi-file status lines to use the active spinner icon directly instead of replacing a static icon, ensuring consistent liveness cues.
- Centralized archive operations into a new `utils/zip.ts` module with unified support for ZIP, tar, and tar.gz formats.
- Optimized ZIP reading using lazy, ranged central-directory access and implemented ZIP64 support for large files.
- Hardened archive extraction with directory traversal protection and configured memory limits for loading and extraction.
- Refactored tool-specific logic to utilize the new centralized utility and deleted the redundant `archive-reader.ts`.
- Added explicit ArkType schema descriptions across all coding agent tool definitions.
- Updated schema definitions in autoresearch and commit tools with descriptive wrappers.
- Documented tool schema enhancements in the packages/coding-agent CHANGELOG.
- Migrated all wire protocol, schema definitions, and tools validation from Zod to ArkType across multiple packages.
- Updated extension runtimes, custom tools loader, and TypeBox compatibility shim to expose and use ArkType instances.
- Added a comprehensive ArkType migration guide, validation parity tests, and helper utilities.
- Removed redundant PDF asset routing and parsing implementations from the read tool.
Unwrap bracketed [path#TAG] headers at the top of WriteTool.execute() so internal-URL detection, plan-mode guard, plan path resolution, and ACP bridge routing all see the same filesystem target. Without this, ['/data/workspaces/can1357__oh-my-pi__2472/.omp-session/2026-06-13T20-19-47-341Z_019ec2a3-fc0d-7000-b1e6-25831d3c3ec5/local/scratch.md' slipped past isInternalUrlPath() and was bridged to the editor instead of staying on disk as a session-local artifact.\n\nFixes #2472
- Added a reusable notice constant for executable write operations.
- Appended the executable notice to write-result output whenever a file was made executable.
Individual conflict resolution now bypasses the LSP writethrough to prevent formatting from corrupting other unresolved marker blocks and to avoid noisy diagnostics in partially resolved files.
- Added transcript and assistant block version tracking for finalized segments.
- Changed committed block reuse logic to require prior finalization and same version.
- Fixed rerendering of committed finalized blocks when version values changed.
Addresses all three review concerns from @roboomp and @chatgpt-codex-connector:
1. **Contract regression fixed**: guard
(extracted from ) is now called by all four write sites.
Internal-URL paths (e.g. ) and the active plan file
in plan mode are never routed to the editor bridge.
2. **Bridge call hygiene**: bridge calls are now wrapped in ,
is called, and
is bumped — matching the contract already had.
3. **Tests**: adds 6 parity tests
(2 per write site) mirroring :
- routes plain workspace writes through the bridge, skips writethrough
- writes local plan artifacts to disk instead of the ACP bridge
**Shared module**: exports
and (guard +
bridge call + ToolError wrap + invalidateFsScanAfterWrite +
bumpFileMutationVersion). All four write sites call it; the duplicated
6-line pattern is gone. is simplified to use the same helper
instead of its private method.
vault writes now rated write-tier and plan-mode enforced; .tar.gz rewrites keep gzip, are atomic, and write through symlinks; CRLF conflict detection works; conflict twins only invalidated when truly stale; ask discloses timeout auto-selection in result and transcript; todo rejects duplicate ids and stops persisting half-applied batches; auto-generated guard validates against mtime+size; ACP writes run post-write bookkeeping; irc errors set isError.
- Added status.done and tool.* symbols to theme mappings and presets.
- Replaced generic success glyphs with contextual +/-, tool icons, and warnings.
- Mapped tool/task/job completions to status.done or status.enabled with icon overrides.
- Triggered runtime provider refresh after extension registration and warned on failure.