- Implemented file deletion (`REM`) and movement (`MV`) operations within the hashline grammar and parser.
- Added filesystem support for executing delete and move commands while maintaining snapshot history migration.
- Integrated file operation detection and parsing logic into the coding agent and patcher components.
- Added comprehensive integration tests and documentation for the new file-level operation syntax.
- Automatically rebind edits to the correct file when an authored path does not exist but the filename and snapshot tag uniquely match a file read earlier in the session.
- Prevent path recovery for paths that would escalate write privileges, ensuring compatibility with read-only internal URL targets.
- Surface warning messages to the model and user upon successful path recovery to encourage correct future path usage.
- Improved delimiter-balance logic to correctly identify and spare partially deleted structural closers.
- Prevented premature deletion of structural closers by accounting for existing code below the modification range.
- Added support for tracking inserted lines to improve boundary repair accuracy across multi-section updates.
- Refined the suffix-closer identification to skip lines restated by the new payload and account for projected closers appearing after the patch.
- Updated logic to verify if the patch prefix already satisfies missing structural openers before sparing deleted suffix lines.
- Fixed a bug where replacement payloads that restated existing suffix tails caused erroneous retention of structural closers.
The dropped-closer repair fired per replacement group, so a `SWAP` that
deleted a structural closer kept it even when another hunk had already
removed the matching opener (a deliberate wrapper removal) — leaving a
stray `}` and corrupting valid multi-hunk edits.
Defer the repair to a second pass that sums each hunk's delimiter delta
per contiguous hunk (so backtick/block-comment state never bleeds across
non-adjacent hunks), suppresses it when the matching opener was deleted or
replaced just above the range, and consumes the residual per repair so a
genuine missing closer elsewhere in the patch still fires.
Fixes#3142
- Clarified the message instructing users or models on how to handle unseen lines.
- Added specific instructions recommending a ranged read to bypass summarization and mint a fresh tag.
Replaced the one-sided JSX echo guard regex with a small scanner that ignores tag-closing characters inside quotes and expression braces, so self-closing tags with comparison props still allow boundary-echo repair.\n\nFixes #2705
Scanned replacement payload prefixes as one JSX/XML fragment so the single-line boundary echo guard preserves nested closers whose opener spans multiple lines.\n\nFixes #2705
Avoided treating a single-line replacement payload's own JSX/XML closing tag as an off-by-one echo when the payload opened the same tag.\n\nFixes #2705
Auto-repaired single-line replacement expansions that retype a surviving JSX/XML closing boundary below the edited line, preserving ordinary statement duplicates while removing the block-end echo.\n\nFixes #2705
- Renamed line and block patch op verbs to XCHG, DEL, and INS in parsing and formatting.
- Updated grammar and tokenizer to support XCHG.BLK, DEL.BLK, and INS.PRE/POST/HEAD/TAIL forms.
- Updated diagnostics, docs, prompts, tests, and changelog to use XCHG/DEL/INS-based operators.
- Expanded session-stats parsing to normalize legacy op aliases to compact IDs.
- Tracked seen-line provenance in snapshots and propagated it from read/search/ast-grep rows.
- Rejected hashline edits on unseen lines before patching, throwing unseen-line errors.
- Rejected single-line block anchors in strict mode and dropped them in unresolved lenient mode.
- Trimmed one-sided keeper-echo duplicates during multi-line replacements with warning output.
- Updated boundary repair to skip dropping closing suffix lines when the replacement payload already restates them.
- Added a helper that checks whether a replacement payload ends with the same trailing deleted lines before sparing structural closers.
- Added a boundary repair test that confirms a replacement preserving an internal closer produces no duplicate closer or warning.
- Added a focused-agent left-key input listener that consumes double left taps when the input is empty.
- Routed focused session left-tap behavior through #handleFocusedLeftTap so it matches the Esc-style unfocus timing.
- Updated tests/fixtures for the new listener flow and refreshed a hashline block-edit error assertion.
- Added a SessionFocusController to switch transcript and input context between main and subagent sessions.
- Added agent-hub Enter activation and double-left return behavior for focused local agents.
- Added view-session-based event and render logic to avoid stale focus-session state.
- Added status-line focused agent display with ghost icon and focused-mode border dimming.
- Handled unresolvable `insert after block` edits by lowering them to plain `insert after` operations with a warning when no syntactic block can be resolved.
- Added a new `insertAfterBlockUnresolvedLoweredWarning` message and narrowed unresolved-block errors to replace/delete paths.
- Updated block tests to validate warning-based lowering for missing resolvers and blank/invalid `insert after block` anchors.
- Scope.
- Added a trailing-sentinel guard to identify newline-generated phantom lines and drop delete edits targeting them.
- Updated edit validation to allow those no-op deletes while preserving real line bounds checks.
- Adjusted format-v2 tests to expect no-op handling of sentinel deletes and clipping for ranges ending at the sentinel.
- Updated block resolution to detect structural-closing-line anchors and convert unresolvable `insert after block` edits into plain `insert after` inserts while emitting a dedicated warning.
- Propagated these resolver warnings through `PatchSection` and `Patcher` results so parse and application callers receive them.
- Added tests covering the closer-anchor fallback and confirming non-closer unresolved block anchors still throw.
- Fixed deep insert-after-block landing by retreating inward corrections across trailing closers.
- Added blockStart tracking and warning diagnostics for inward correction of block inserts.
- Clarified insert-after-block prompt and changelog guidance to require opener-based landing rules.
- Added regression tests for nested, empty, and conflicted inward landing scenarios.
Updated the hashline edit prompt and internal edit docs to make insert-after-block anchors opener-only, and added regression coverage for closing-delimiter anchors and prompt guidance.\n\nFixes #2292
- Added a shared `formatAnchoredContext` helper and switched mismatch formatting to use it.
- Extended unresolved block-edit errors to append nearby numbered context with `*`-marked anchor lines.
- Updated unit and integration tests and docs to reflect the new unresolved-block preview behavior.
- Separated non-contiguous diff regions with a single blank gap row, normalized after block-context insertion.
- Rendered gap rows as one dim ellipsis in the TUI and HTML export.
- Applied the same blank-separator dedupe and edge-trimming to hashline's compact diff preview.
- Rendered added/current lines without `+`/space prefix padding.
- Collapsed long added runs with a bare `…` marker instead of `+…`.
- Normalized adjacent ASCII/Unicode elision markers to one `…`.
- Added matching-bracket utilities to locate partner lines for visible spans.
- Added read tool output to use displayContent text and startLine for bracket-aware previews.
- Added matching-bracket context rows to generateDiffString and generateUnifiedDiffString.
- Adjusted diff row insertion to deduplicate and keep contiguous changed groups together.
- Removed the mid-skip placeholder line that was output when skipping lines in the middle of a diff, relying instead on the line number jump to convey the gap. Removed the corresponding placeholder-filtering logic from the hashline diff preview that was handling these placeholders.
- Modified buildCompactDiffPreview to omit removed lines from output while preserving removal counts for offset tracking.
- Added logic to collapse long contiguous added runs with +<lineNum>... elision marker, keeping configurable edge lines on each side via new maxAddedRunContext option.
- Removed context-gap placeholder rows (... or ...) from model-facing preview, relying on line-number jumps to convey elision.
- Reorganized test suite by moving core contract tests to dedicated core-contracts.test.ts file and diff-preview tests to diff-preview.test.ts for better separation of concerns.
- Added a BlockResolution type and `onResolved` callback so `resolveBlockEdits` reports each anchor's resolved span for `replace block`/`delete block` edits.
- Updated patch application to return those spans on hash-match applies and omit them during drift-recovery paths where line numbers no longer align.
- Propagated the surfaced spans through the edit tool output and added/updated tests covering replace/delete block echo and drift behavior.
Defer read-output line-number stripping from #handleRaw to #flushPending and
gate it on uniformity: a bare "N:text" row is only a pasted-snapshot artifact
when *every* bare body row in the hunk carries the prefix. A mixed set (e.g.
"3:keep" next to "plain") is treated as genuine content and left intact,
avoiding silent corruption of bodies that legitimately start with "digits:".
Removes at most one prefix per row; "+"-prefixed literal rows stay untouched.
Reverts the now-orphaned stripLeadingHashlinePrefixes export back to private.
- Replace recursive stripLeadingHashlinePrefixes with single-pass
stripOneLeadingHashlinePrefix in #handleRaw to prevent over-stripping
content whose own text starts with digits:colon (e.g. YAML ports,
timestamps: 2:42:hello → 42:hello, not hello)
- Export stripOneLeadingHashlinePrefix from prefixes.ts
- Move hashline CHANGELOG entry to [Unreleased] section
- Add regression tests for nested N: prefix and +N: asymmetry
- Replaced `¶path#hash` prefix with `[path#hash]` delimiters across parser, tokenizer, and grammar.
- Updated prompts, docs, and recovery paths to the new bracketed form.
Aligned the runtime header parser with the formal grammar's no-`#`-in-filename rule: any `#` left in the path body after detecting the trailing `#XXXX` tag means the header is malformed (short `#1A2`, non-hex `#1A2G`, over-long `#1A2B5`, stale-tag copy-paste, line-suffixed tags), not a path with an embedded hash. Mirrored the same rule on the apply_patch recovery path.
Added strict and recovery regression coverage for the three malformed-tag shapes the reviewer named.
Rejected headers such as ¶src/file.ts#1A2B:42 as malformed headers instead of treating the whole tail as a hashless path and failing later in body parsing.
Added strict and apply_patch-recovery regression coverage for line-suffixed snapshot tags.
Tightened the relaxed header parser so a 4-hex token sitting before whitespace + more content (e.g. `¶src/a.ts#1A2B copied from read`) still raises the focused "must be ¶PATH or ¶PATH#TAG" diagnostic instead of being silently re-interpreted as a hashless path.
Also stopped rejecting hashless paths whose last five characters look like #TAG with a non-hex digit, and mirrored the same anti-junk rule in the apply_patch recovery parser.
Parsed hashline section headers by recognizing only a trailing #TAG as the snapshot delimiter, allowing whitespace inside valid paths.
Updated recovery parsing and grammar docs to match the runtime parser, and added regression coverage for canonical and recovered headers with spaces.
Fixes#1634
- Updated the grammar to parse replace hunks with zero body lines.
- Changed empty replace execution to emit delete edits across the target range.
- Updated tests to verify empty replace syntax deletes lines while empty inserts still throw errors.
- Removed the structural-closer-only guard, allowing single duplicated opener lines (e.g. `foo(`, `if (x) {`) to be dropped when they exactly explain the delimiter imbalance.
- Added early-exit in `findDuplicatePrefix`/`findDuplicateSuffix` when delta is zero, preserving intentional duplicates of ordinary statements.
- Added tests covering the `planRender(` opener case and the no-repair case where the duplicate does not account for the imbalance.
Used the leading/trailing maxima directly and skipped repair when their sum covers the whole payload, so multi-line boundary echoes can no longer trim explicit replacement content.
Added regression coverage for the A,B,old,C,D → A,B,C,D scenario.
Avoided boundary-echo repair when trimming the echoed neighbors would remove the entire replacement payload.
Added regression coverage for exact replacement semantics when a payload intentionally duplicates both neighbors.
Absorbed replacements whose payload restates unchanged leading and trailing boundary lines around the selected range.
Added regression coverage for duplicated function headers and trailing statements.
Fixes#1664
- Added `replace block N:` syntax in grammar/parser/tokenizer/types, emitting `kind: "block"` edits with empty-body checks.
- Added block-resolution in hashline apply/recovery, wiring `BlockResolver` to resolve edits with throw/drop unresolved behavior.
- Added native `blockRangeAt` support and exported block range/options types through pi-ast, pi-natives, and JS bindings.
- Added coding-agent resolver wiring plus internal visibility/exports updates and new parser, patcher, and setup-wizard tests.
- Made `#TAG` required on every file section; removed the hashless-header grammar form.
- Head/tail inserts with a stale tag now apply and emit `HEADTAIL_DRIFT_WARNING` instead of hard-failing.
- Anchored edits and missing files now surface write-tool guidance in error messages.
- Updated prompt docs to document no-hashless-form rule and stale-tag recovery guidance.
- Replaced snapshot internals with full-file records and removed contiguous/sparse snapshot APIs.
- Added file-hash normalization, computed `computeFileHash`, and updated grammar/messages to 4-hex tags.
- Simplified recovery by checking whole-file hashes first, then applying merge-replay fallback after mismatches.
- Updated coding-agent tools to use `record`/`recordFileSnapshot` and skip hash headers for unsnapshotted large files.
- Expanded patcher and snapshot tests to verify 4-hex anchors, hash deduplication, and cache-capped behavior.
- Replaced bare `A B` range headers with `replace N..M:`, `delete N..M`, `insert before N:`, `insert after N:`, `insert head:`, and `insert tail:`.
- Removed `&A..B` repeat rows; insert-before/after ops now express the same intent explicitly.
- Empty replace bodies now error instead of deleting; `delete` is the canonical deletion op.
- Updated grammar, prompt, docs, tests, and all call sites to the new syntax.
- Replacement hunks now drop duplicated closing delimiters restated in the payload but surviving just outside the range.
- Ranges that swallow a structural closer the payload omits now spare that closer instead of deleting it.
- Each repair surfaces a `delimiter-balance` warning through `ApplyResult.warnings`.
- Brackets inside strings, template literals, and comments are skipped to avoid false positives.
- Coalesced overlapping and abutting same-path reads in InMemorySnapshotStore into one existing tag.
- Folded disjoint but consistent reads into a single SparseSnapshot tag when their shared lines matched.
- Minted a new InMemorySnapshotStore tag when shared lines disagreed, treating the view as a changed file.