Files
oh-my-pi/packages/hashline/README.md
T
can1357 b12e4698a6 feat: added @oh-my-pi/hashline package and migrated hashline tooling
- Added a dedicated @oh-my-pi/hashline package with parser, patcher, filesystem, snapshots, and release metadata.
- Migrated coding-agent hashline and stream entrypoints to @oh-my-pi/hashline and removed old hashline module exports.
- Changed multi-section hashline execution to validate section hashes and flush diagnostics only at the final commit.
- Added session fileSnapshotStore support and rewired edit/read/search/write tools to use it instead of fileReadCache.
2026-05-27 04:03:49 +02:00

2.5 KiB

@oh-my-pi/hashline

A compact, line-anchored patch language and applier.

Hashline is a diff format designed for LLM-driven file edits. It binds every hunk to a file-content hash so stale anchors are rejected before they corrupt code, and it abstracts over the filesystem so the same patcher works on disk, in memory, over the network, or against any custom backend.

Quick start

import {
	Filesystem,
	InMemoryFilesystem,
	InMemorySnapshotStore,
	Patcher,
	Patch,
} from "@oh-my-pi/hashline";

const fs = new InMemoryFilesystem();
await fs.writeText(
	"hello.ts",
	`const greeting = "hi";\nexport { greeting };\n`,
);

const patcher = new Patcher({ fs });
const patch = Patch.parse(`¶hello.ts\n1:\n+const greeting = "hello";`);
const result = await patcher.apply(patch);

console.log(result.sections[0].op); // "update"
console.log(await fs.readText("hello.ts"));

Format

See src/prompt.md for the user-facing description and src/grammar.lark for the formal grammar.

Each hunk starts with a ¶PATH#HASH header. The hash is a 4-hex-character xxHash32 truncation of the file's LF-normalized content. The hash protects against stale anchors: if the file changed between the read that produced the hash and the edit, the patcher refuses (or, with a SnapshotStore, tries session-aware recovery).

Inside a hunk:

Op Meaning
LINE↑ Insert before LINE (or BOF↑ for the beginning of file)
LINE↓ Insert after LINE (or EOF↓ for the end of file)
A-B: Replace lines A..B (single-anchor A: is sugar for A-A:)
A-B! Delete lines A..B (single-anchor A! is sugar for A-A!)
+TEXT Payload continuation. The + prefix is stripped

Abstractions

Filesystem

Read and write text by path. The default implementations:

  • InMemoryFilesystem — backed by a Map. Tests, sandboxes.
  • NodeFilesystem — disk-backed via Bun.file/Bun.write. Default for CLIs.

Subclass Filesystem to wire hashline into any storage: VFS, S3, an LSP text-document protocol, a Git tree, anything.

SnapshotStore

Optional. When provided to Patcher, hashline tries to recover from a stale section hash by replaying the edit against a cached pre-edit snapshot of the file and 3-way-merging onto the current content. See recovery.ts.

Patcher

The orchestration class. Reads, normalizes line endings + BOM, applies edits, restores line endings, and writes via the configured Filesystem. Multi-section patches are preflighted up front so a partial batch never lands.