Commit Graph

128 Commits

Author SHA1 Message Date
roboomp 1865afb7c4 fix(hashline): recovered pipe-numbered read rows
Accepted pipe separators in snapshot-row recovery and bare-body prefix stripping, matching non-hashline read and search output.

Fixes #7905
2026-08-07 12:21:27 +00:00
can1357 ab78d3091e fix(hashline): warn instead of erroring on empty named-register paste
PUT ... @name with no matching capture no longer fails the patch: it
pastes nothing (a span target is still removed, i.e. it degrades to a
cut) and surfaces a warning naming the available registers. Anonymous
empty/ambiguous pastes still error. validateClipboardSequence now only
guards anonymous sequencing; applyEdits threads clipboard warnings into
ApplyResult.warnings.
2026-08-07 06:00:08 +02:00
can1357 e9888367d1 refactor: migrated packages to internal utility modules and removed external dependencies
- Implemented in-house, zero-dependency utility modules in `pi-utils` covering DOM manipulation, markdown parsing, templating, browser automation helpers, and terminal buffers.
- Migrated packages across the repository to consume the new internal utilities and `omptype` schema validators instead of external dependencies.
- Removed multiple external runtime and development dependencies including Zod, Marked, LRU cache, Turndown, and Puppeteer browser packages.
2026-08-05 13:39:09 +02:00
metaphorics 3802d2dd80 chore(ts): enforce noImplicitOverride 2026-08-05 02:49:01 +09:00
can1357 25299693c9 feat(hashline): updated grammar and documentation for unified put and cut syntax
- Update Lark grammar to support the unified put, cut, move, and remove operations.
- Update documentation and prompts to reflect canonical inclusive range separators and named register rules.
2026-07-31 00:28:54 +02:00
can1357 5ea583e413 feat: replaced legacy editing commands with unified put and cut syntax
- Replaced legacy `SWAP`, `INS`, and `PASTE` commands with unified `PUT` and `CUT` hunks across parser, grammar, tokenizer, and test suites.
- Added support for named registers and span paste operations in clipboard and block execution logic.
- Implemented indentation repair and enhanced gap locator formatting for improved patch resilience.
- Updated documentation, system prompts, and session analysis scripts to reflect the new syntax and header shapes.
2026-07-31 00:19:52 +02:00
can1357 9856f904d7 feat(typescript-edit-benchmark): introduced empirical edit mutation planning
- Add new structural, multi-edit, and block-level mutation classes with updated category mappings.
- Introduce hunk extraction, placement, rendering, and solver utilities along with unit tests.
- Implement size-based mutation planning, prompt validation logic, and new prompt markdown templates.
- Update benchmark generation scripts and package configurations to support empirical edit shape statistics.
2026-07-30 07:45:01 +02:00
can1357 e05f229f43 refactor: standardized editing syntax by removing copy and delete operations
- Removed copy and delete operations across tokenizer, parser, grammar, and clipboard logic.
- Standardized line-editing operations and block resolvers to use cut exclusively.
- Updated documentation, prompts, and test suites to reflect the removal of copy and delete syntax.
2026-07-30 07:42:48 +02:00
can1357 b9ae2a3f9b docs(hashline): condensed and clarified instructions in prompt documentation
- Condensed instructions and rule descriptions in `packages/hashline/src/prompt.md`.
- Streamlined formatting examples and anti-patterns for clarity.
- Clarified block operation boundaries and markdown heading section rules.
2026-07-30 07:21:44 +02:00
can1357 aaa1ff4e3f refactor(hashline): restructured Lark grammar rules to reduce complexity
- Regrouped `grammar.lark` around shared `target` and `pos` rules, reducing hunk rules from twelve to seven.
- Maintained byte-identical language acceptance while simplifying internal grammar structure.
2026-07-30 07:21:44 +02:00
can1357 9aada058ee feat(hashline): implemented clipboard operations in hashline engine
- Implemented clipboard register management, parsing, and execution rules for CUT, COPY, and PASTE operations in the hashline engine.
- Added session-persistent clipboard state and integration across agent session execution, diff previews, and streaming tools.
- Added comprehensive validation, error messages, recovery handling, and test coverage for clipboard and block operations.
2026-07-30 07:21:43 +02:00
Márton Danóczy 7708f372b5 fix(hashline,coding-agent): key snapshot tag on actually-persisted content after ACP bridge writes
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)
2026-07-29 23:08:38 +02:00
can1357 44907cef75 fix(hashline): secured parser against unsafe integers and large ranges
- Validate line numbers as safe integers and reject values exceeding `Number.MAX_SAFE_INTEGER`.
- Impose a maximum expansion limit of 100,000 lines on patch ranges to prevent memory and CPU exhaustion.
- Inline delete range iteration directly into execution to avoid allocating intermediate anchor arrays.
2026-07-29 21:18:50 +02:00
can1357 972ddb4e5e fix(edit): reduced hashline failures for weak models
- Added actionable reversed-range and block-anchor diagnostics.
- Accepted unambiguous single-dot ranges and routed affected models to replace mode.
- Preserved edit safety checks and added regression coverage.

Fixes #6671
2026-07-27 05:57:12 +02:00
can1357 03e6564c05 feat(hashline): enabled leniency rule for bare bullet minus rows
- Add leniency rule in parser to auto-accept bare `-` rows as literal content when hunks represent Markdown bullet lists.
- Emit MINUS_BULLET_AUTO_PIPED_WARNING when bullet-shaped rows lack explicit plus prefixes.
- Reject ambiguous or non-bullet minus rows to prevent unified-diff contamination.
2026-07-24 15:36:32 +02:00
can1357 52ad6516ef feat(diff): implemented native UTF-16 diff processing and removed jsdiff
- Implemented native UTF-16 text processing in Rust diff module with support for unpaired surrogates.
- Removed `similar` crate from Rust workspace and `diff` npm package from coding-agent, hashline, and natives.
- Removed jsdiff fallback wrappers and `isWellFormed()` guards from TypeScript diff implementations.
- Added comprehensive test suite for native diff functions covering random inputs and edge cases including surrogates and emoji.
- Renamed model `codex-auto-review` to `gpt-5.3-codex-spark` with updated pricing and context window.
2026-07-23 01:35:31 +02:00
Wolfgang Schoenberger 8f17a0300d fix(natives): reject ill-formed UTF-16 in native diff and fall back to jsdiff 2026-07-22 04:32:46 -07:00
Wolfgang Schoenberger 2b7707e6d7 perf(coding-agent): use native diff for edit diffs, intra-line word diff, and hashline recovery 2026-07-22 01:24:43 -07:00
can1357 f8e7b29b70 fix(hashline): rejected trailing colon on DEL headers
- `DEL N:` previously consumed the colon and body rows then failed with the
  wrong guidance; it now falls through to contamination detection which
  emits the corrective "has no colon" message, matching `DEL.BLK N`.
- Aligns tokenizer with the leniency removal in 766790cba.
2026-07-17 21:53:57 +02:00
can1357 766790cbac chore: unclanking edit pr 2026-07-17 21:37:20 +02:00
roboomp b65467291e fix(edit): recovered malformed local-model ranges
- Accepted comma-separated ranges and harmless malformed trailers emitted by local models.
- Added focused array-input diagnostics and reinforced canonical hashline syntax in the edit prompt.
- Covered the recovered forms with behavioral regression tests.

Fixes #5805
2026-07-17 07:46:25 +00:00
can1357 d50cc4e2d3 feat(coding-agent): made hashline seen-line guard opt-in via edit.enforceSeenLines
- Added the `enforceSeenLines` option to hashline `PatcherOptions` (defaults `true`); the seen-line guard in `Patcher` now runs only when enabled.
- Added the `edit.enforceSeenLines` coding-agent setting (default off) and wired it through `edit/hashline/execute.ts` into the `Patcher`.
- Stopped `file-snapshot-store` excluding column-clipped (>512-char) lines from a snapshot's seen set, so single-line edits on long lines apply without a full-width re-read.
- Updated `seen-line-guard` tests and the hashline/coding-agent changelogs.
2026-07-15 15:15:08 +02:00
can1357 a886a30901 feat(hashline): standardized drift recovery using anchor remapping
- Replaced 3-way-merge and session-chain replay strategies with a consistent anchor remapping flow for drift recovery.
- Removed legacy reconciliation logic and associated session-replay warning constants.
- Updated recovery flow to mandate anchor consistency and validate against duplicated context.
- Refined test suite to verify anchor mapping mechanics and explicit refusal of ambiguous remappings.
2026-07-13 16:23:00 +02:00
can1357 e45796908b feat(hashline): implemented strict validation for boundary repairs
- Introduced strict validation for boundary repairs to prevent accidental code deletion when payload context is insufficient.
- Added `ambiguousBoundaryEchoMessage` to identify when a partial echo is too short to safely replace a range.
- Added `ambiguousCloserSpareMessage` to identify when a spare closer replacement lacks structural evidence (indentation or delimiter balance) for placement.
- Implemented rejection logic in `repairReplacementBoundaries` for ambiguous cases, forcing the user to provide explicit edits instead of guessing.
- Added test cases covering one-sided echo and ambiguous closer sparing to ensure errors trigger on unsafe edits.
2026-07-13 10:37:21 +02:00
can1357 1301d5b07a Merge remote-tracking branch 'origin/farm/f5b6b32e/fix-edit-anchor-fresh-read' 2026-07-02 23:43:10 +02:00
can1357 0059aed4f0 feat(hashline): enabled content hash matching to resolve tag collisions
- Simplified match logic to rely exclusively on content hash equality.
- Removed strict validation that rejected colliding snapshot tags.
- Updated recovery behavior to resolve collisions to the most-recently recorded snapshot.
- Refactored tests to expect successful preview and patching despite tag ambiguity.
2026-07-02 22:45:29 +02:00
roboomp 367a002e48 fix(hashline): column-cap revealed anchor lines and gate merge on width truncation
Codex reviewer flagged that the per-reveal cap only limits the line
count, not each line's width. A minified-bundle-style wide line
(megabytes on one row) would be stored verbatim in the RevealedLine
and formatted straight into the thrown edit error — bypassing the
column-truncation read/search already apply to long lines and dumping
that much content into the tool result, TUI, and model context.

assertSeenLines now clips each revealed line at
SEEN_LINE_REVEAL_MAX_COLUMNS (512, matching search's DEFAULT_MAX_COLUMN)
with a trailing ellipsis marker and treats any clip as truncated. The
existing truncated-gated merge keeps the guard closed on clipped
reveals so the model cannot land an edit having only seen the first
512 chars of a wide line, and the message keeps the range-re-read
guidance.
2026-07-02 08:20:47 +00:00
roboomp f42fa38f7c fix(hashline): do not merge revealed seen-lines on the truncated path
Codex reviewer flagged that when an anchor range exceeds
`SEEN_LINE_REVEAL_CAP`, merging the revealed prefix into `seenLines`
lets a model split a blind over-cap edit into two <=cap-line retries
and slip past the range-re-read gate: attempt 1 reveals+merges lines
100-139, attempt 2 reveals+merges the 140-159 tail, attempt 3 applies
— all without a single range read.

The merge is now gated on `truncated === false`: only a reveal that
covered EVERY unseen anchor line joins `seenLines`. Truncated reveals
keep the range-re-read guidance and the reveal window stays anchored
at the head across retries, so the same over-cap patch keeps rejecting
until the model actually re-reads the range.
2026-07-02 08:11:16 +00:00
roboomp 72a30af57c fix(hashline): reveal seen-line-guard content and merge into snapshot on reject
Structural-summary reads (default for parseable code >100 lines) mint a
`[path#tag]` that only marks declaration/boundary lines as displayed;
edits anchored inside an elided body then hit `#assertSeenLines` in
`packages/hashline/src/patcher.ts` and reject with "never displayed
(it showed a partial range, a search hit, or a folded summary)". The
existing message pointed at a range re-read, but that made every such
recovery a three-turn round-trip (edit-fail → range read → edit-retry)
and models frequently retried the same edit instead of following the
hint — 5-8 out of 10 edits failed for the reporter.

The rejection now:
- Inlines the actual file content at the unseen anchor lines, from
  `matchedSnapshot.text` (which by definition equals the live normalized
  content on the no-drift path), up to `SEEN_LINE_REVEAL_CAP` (40) lines.
- Merges the revealed lines into the snapshot's `seenLines` set, so a
  straight retry with the same `[path#tag]` header succeeds without a
  follow-up read. The content is inside the error the model receives,
  which is the proof it has now seen those lines.
- For anchor ranges over the cap, only the revealed prefix is merged;
  the message keeps the range-re-read guidance for the remainder so
  runaway blind edits don't sneak past.

Fixes #4224
2026-07-02 08:05:12 +00:00
can1357 0fb1dcbc1a Merge remote-tracking branch 'origin/farm/edc4af0a/markdown-edit-escape-prompt' 2026-07-02 02:03:01 +02:00
can1357 b821aa977e fix(hashline): introduced collision-safe tag lookup by exact hash
- Added `byHashExact` to `SnapshotStore` to resolve historical versions only when a tag is unambiguous.
- Prevented recovery and edit-preview paths from incorrectly applying anchors against colliding tags.
- Implemented `InMemorySnapshotStore.byHashExact` returning null when multiple recorded versions share a tag.
- Added comprehensive unit tests validating single-match resolution and multi-collider rejection.
2026-07-02 01:51:09 +02:00
can1357 f5d090829f refactor(hashline): optimized anchor validation and added collision safety
- Accelerates duplicate-line verification from quadratic $O(N^2)$ to linear $O(N \log N)$ by precomputing anchor neighbors in a single sorted pass.
- Optimizes duplicate checks to $O(1)$ by collecting line values into a pre-allocated Set instead of repeatedly searching arrays.
- Prevents silent content corruption by aborting recovery if multiple historical snapshots share the same 16-bit hash tag.
- Validates the optimized duplicate-line shifting behavior and collision rejection logic with new test coverage.
2026-07-02 01:51:09 +02:00
roboomp cf5150568f fix(edit): taught markdown bullet escaping
Clarified hashline minus-row errors and model-facing prompt examples so Markdown list rows use the + body-row prefix instead of triggering write fallbacks.

Fixes #4179
2026-07-01 22:15:53 +00:00
can1357 5f1ed0fcde chore: reformat 2026-07-01 23:14:36 +02:00
can1357 efee86afe5 fix(hashline): reject ambiguous colliding snapshot tags 2026-07-01 21:53:16 +02:00
can1357 28843ec015 Merge PR #4113: fix(hashline): guarded against 16-bit snapshot tag collisions (@roboomp) 2026-07-01 21:53:15 +02:00
can1357 4c751c48a8 fix(hashline): validate unique stale anchor remaps 2026-07-01 21:42:26 +02:00
can1357 3e4ac085aa Merge PR #3778: fix(hashline): recover stale edit anchors after line shifts (@roboomp) 2026-07-01 21:42:26 +02:00
roboomp b081c8abaf fix(hashline): guarded against 16-bit snapshot tag collisions
The visible 4-hex hashline tag is the low 16 bits of a non-cryptographic hash, so two genuinely different file states can collide. Snapshot storage keyed dedup on the hash alone, fusing distinct texts (and their seenLines) into one stored entry. The patcher treated `computeFileHash(live) === expected` as an exact live match and took the no-drift path — applying line-anchored edits directly to unrelated live content and bypassing recovery.

Keeps the visible tag format for backward compatibility and widens identity at the two junctures where it matters:

- Store dedup now compares (hash, text). Distinct texts with the same 4-hex tag are retained as separate versions with independent seenLines; identical repeated reads still fuse as before.

- New abstract SnapshotStore.byContent(path, text) disambiguates collisions by content.

- Patcher requires the stored snapshot for (path, expected) to equal live text before taking the no-drift path. On collision it falls through to Recovery, whose line-precise 3-way merge fails cleanly on colliding-but-different content and raises MismatchError. When no snapshot is retained for the tag, behavior is unchanged (external mint / aged out).

- #assertSeenLines now consults the exact matched snapshot, so seen-line validation cannot read a collider's provenance.

Regression tests added to both snapshots.test.ts and patcher.test.ts covering the concrete `1D84` pair from the reporter.

Fixes #4075
2026-07-01 07:08:13 +00:00
roboomp 7ec00a5007 fix(edit): skipped notebook bom sniffing
Skipped binary BOM detection for notebook-backed hashline reads so virtual cell text is serialized without a leading U+FEFF marker.
2026-06-30 05:58:01 +00:00
roboomp d7c6472824 fix(edit): preserved hashline utf-8 bom
Added binary BOM detection to the hashline patcher and filesystem adapters so edits restore BOM bytes when text decoding hides U+FEFF.

Fixes #3867
2026-06-30 05:48:37 +00:00
roboomp d54ca6085a fix(hashline): rejected ambiguous anchor remaps
- Rejected duplicate-line stale anchor remaps unless surrounding context still maps around the target.
- Added regression coverage for duplicate-line drift that would overwrite the wrong occurrence.

Fixes #3775
2026-06-29 03:02:25 +00:00
roboomp 234d2dab49 fix(hashline): remapped stale edit anchors
- Remapped stale hashline anchors through unchanged-line diffs after prior insertions or deletions shifted targets.
- Added regression coverage for in-session insertion and deletion drift.

Fixes #3775
2026-06-29 02:53:00 +00:00
luk 00b08cc8a2 fix: tolerate GLM 5.2 stray dot in hunk headers
GLM 5.2 inserts an extra `.` between the line number/range and the
trailing `:` (e.g. `SWAP 2.=3.:`, `INS.POST 2.:`, `DEL 2.=3.`).
The parser failed with "payload line has no preceding hunk header"
and could not recover. Add a `skipStrayDot` helper that skips a
spurious `.` before the optional colon or end-of-line, wired into
`consumeOptionalColon` (covers SWAP, INS.*, SWAP.BLK, INS.BLK.POST)
and the DEL / DEL.BLK branches.
2026-06-28 21:15:51 +01:00
can1357 eb39fc4a50 refactor(hashline): simplified snapshot relocation and remove unused filesystem method
- Removed the unused `delete` method from `InMemoryFilesystem`.
- Updated `relocate` to create new snapshot objects instead of mutating shared references.
- Simplified the merging logic in `relocate` to handle history concatenation more cleanly.
2026-06-27 01:00:56 +02:00
can1357 b612e8c792 feat(hashline): allowed file deletion and movement operations
- 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.
2026-06-27 00:33:31 +02:00
can1357 55b02a568d feat(coding-agent): improved local artifact sandbox handling and path recovery
- Enabled tag-based path recovery for artifacts within the session `local://` sandbox.
- Restructured `hashline` path recovery logic to ensure preflight validation runs on resolved paths.
- Prevented ACP editor buffer routing for session `local://` sandbox artifacts.
- Added comprehensive tests covering sandbox target identification and recovery for bare file names.
2026-06-26 16:39:48 +02:00
can1357 02f870fb20 feat: supported markdown section operations for block edits
- 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.
2026-06-26 16:14:23 +02:00
can1357 c46216742b feat(hashline): implemented tag-based patch path recovery
- 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.
2026-06-25 13:14:05 +02:00
can1357 45f074995a fix(hashline): improved delimiter-balance boundary repair logic
- 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.
2026-06-22 06:04:04 +02:00