@skylence-ai/hashline 0.1.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,5 +1,9 @@
1
1
  # hashline
2
2
 
3
+ [![npm](https://img.shields.io/npm/v/@skylence-ai/hashline.svg)](https://www.npmjs.com/package/@skylence-ai/hashline)
4
+ [![CI](https://github.com/skylence-be/hashline/actions/workflows/ci.yml/badge.svg)](https://github.com/skylence-be/hashline/actions/workflows/ci.yml)
5
+ [![License: Apache-2.0](https://img.shields.io/badge/License-Apache--2.0-blue.svg)](LICENSE)
6
+
3
7
  A line-oriented, content-hash-guarded file editor. Instead of `old_string`/`new_string`
4
8
  matching, you address lines by number and bind every edit to a 4-hex content tag of the
5
9
  file. A stale tag (file changed since it was read) is caught before any write, and when
@@ -9,12 +13,10 @@ The engine is written in Rust and ships two interchangeable surfaces over one co
9
13
 
10
14
  | Surface | Entry point | Transport |
11
15
  |---------|-------------|-----------|
12
- | CLI | `hashline read` / `hashline edit` | in-process |
16
+ | CLI | `hashline read` / `hashline edit` / `hashline preview` | in-process |
13
17
  | MCP | `hashline_read` / `hashline_edit` | stdio MCP server |
14
18
 
15
- ## Install / use
16
-
17
- ### MCP (zero-install, recommended)
19
+ ## Quick start
18
20
 
19
21
  Add to your MCP client config (Claude Code, Claude Desktop, etc.):
20
22
 
@@ -25,174 +27,29 @@ Add to your MCP client config (Claude Code, Claude Desktop, etc.):
25
27
  }
26
28
  ```
27
29
 
28
- `npx` downloads the prebuilt binary for your platform on first run. No compiler needed.
29
-
30
- ### CLI via npx
31
-
32
- ```bash
33
- npx -y @skylence-ai/hashline read src/main.rs
34
- echo '...' | npx -y @skylence-ai/hashline edit
35
- ```
36
-
37
- ### cargo binstall (no compile)
38
-
39
- ```bash
40
- cargo binstall hashline
41
- ```
42
-
43
- ### curl / Homebrew
44
-
45
- Download a prebuilt binary directly from [GitHub Releases](https://github.com/skylence-be/hashline/releases) for your platform, or wait for a Homebrew formula.
46
-
47
- ### Docker note
48
-
49
- Using hashline under Docker requires mounting your project directory as a volume so the editor can access files on the host. `npx` (above) is simpler for local dev.
50
-
51
- ### Build from source
30
+ Or use the CLI directly:
52
31
 
53
32
  ```bash
54
- cargo install --git https://github.com/skylence-be/hashline
55
- # or
56
- git clone https://github.com/skylence-be/hashline
57
- cd hashline
58
- cargo build --release
59
- # binary at target/release/hashline
33
+ hashline read src/main.rs
34
+ echo '¶src/main.rs#A1B2\nreplace 2..2:\n+ println!("world");' | hashline edit
60
35
  ```
61
36
 
62
- ## CLI
63
-
64
- ### `hashline read <path>`
65
-
66
- Prints a hashline header followed by numbered lines:
67
-
68
- ```
69
- ¶src/main.rs#A1B2
70
- 1:fn main() {
71
- 2: println!("hello");
72
- 3:}
73
- ```
74
-
75
- Record the `¶path#TAG` header. It anchors subsequent edits to this exact file state.
76
- If the file changes between read and edit the tag becomes stale and the edit is rejected.
77
-
78
- ### `hashline edit [--json]`
79
-
80
- Reads a hashline patch from stdin and applies each section to disk. Exits non-zero
81
- on a stale tag, printing re-read guidance to stderr. Prints the new `¶path#TAG`
82
- header for each section on success.
83
-
84
- The `--json` flag emits a JSON array with one object per section:
85
- ```json
86
- [{"path":"src/main.rs","newHeader":"¶src/main.rs#C3D4","firstChangedLine":2,"warnings":[]}]
87
- ```
88
-
89
- ### `hashline mcp`
90
-
91
- Starts a stdio MCP server exposing `hashline_read` and `hashline_edit` tools.
92
- Compatible with any MCP client (Claude Code, Claude Desktop, etc.).
93
-
94
- ## Patch format
95
-
96
- A patch is one or more sections. Each section begins with a `¶path#TAG` header
97
- (obtained from `hashline read`) followed by edit operations.
98
-
99
- ```
100
- ¶src/main.rs#A1B2
101
- replace 2..2:
102
- + println!("world");
103
- ```
104
-
105
- ### Operations
106
-
107
- | Operation | Syntax | Notes |
108
- |-----------|--------|-------|
109
- | Replace lines | `replace N..M:` + `+`-body | Replaces lines N–M with payload |
110
- | Replace single line | `replace N:` + `+`-body | Shorthand for `replace N..N:` |
111
- | Delete lines | `delete N` or `delete N..M` | No body rows |
112
- | Insert before line | `insert before N:` + `+`-body | |
113
- | Insert after line | `insert after N:` + `+`-body | |
114
- | Insert at top | `insert head:` + `+`-body | |
115
- | Insert at bottom | `insert tail:` + `+`-body | |
116
- | Replace block | `replace block N:` + `+`-body | Tree-sitter block at line N |
117
- | Delete block | `delete block N` | Tree-sitter block at line N |
118
- | Delete whole file | `delete file` | Hash-guarded; no body |
119
-
120
- Body rows are prefixed with `+`. Use `++` for a literal `+` line, `+-` for a literal `-` line.
121
-
122
- ### Create a new file
123
-
124
- Use a tag-less `¶path` header (no `#TAG`) with `insert head:` or `insert tail:` ops.
125
- The file is created if it does not exist; replace/delete ops on an absent path are an error.
126
-
127
- ```
128
- ¶src/new.rs
129
- insert head:
130
- +fn hello() {}
131
- ```
132
-
133
- ### Delete a whole file
134
-
135
- ```
136
- ¶src/old.rs#ABCD
137
- delete file
138
- ```
139
-
140
- ## Content hash
141
-
142
- The tag is a 4-uppercase-hex string derived from the file's normalized content:
143
-
144
- 1. Strip trailing `[ \t\r]` from every line (CRLF-safe)
145
- 2. Compute CRC32 (IEEE polynomial) of the UTF-8 bytes
146
- 3. Take the low 16 bits → format as 4 upper-hex digits
147
-
148
- Internal consistency (same algorithm on read and post-write recompute) is the hard
149
- requirement. The algorithm is documented here so snapshot files remain interpretable
150
- across implementations.
151
-
152
- ## Block operations
153
-
154
- Block ops (`replace block N:` / `delete block N`) resolve the syntactic block beginning
155
- on line N using tree-sitter. Supported languages (by file extension):
156
-
157
- | Extension | Language |
158
- |-----------|----------|
159
- | `.rs` | Rust |
160
- | `.ts` | TypeScript |
161
- | `.tsx` | TypeScript JSX |
162
- | `.js`, `.mjs`, `.cjs` | JavaScript |
163
- | `.jsx` | JavaScript JSX |
164
- | `.py` | Python |
165
- | `.go` | Go |
166
-
167
- The resolver finds the outermost named AST node that begins on line N (excluding the
168
- whole-file root). If no node begins there, or the resolved subtree contains a syntax
169
- error, the op fails with a clear message. Fall back to an explicit line range.
170
-
171
- ## Stale-tag recovery
172
-
173
- When an edit's tag no longer matches the live file, hashline attempts recovery before
174
- hard-failing:
175
-
176
- 1. **3-way merge**: apply the edit to the snapshot that minted the stale tag, then
177
- zero-fuzz merge the resulting diff onto the current file. Emits a warning on success.
178
- 2. **Session-chain replay**: if the snapshot is not the latest, replay the edit directly
179
- onto the current file after verifying line counts and anchor content match.
180
-
181
- Snapshots are stored under `$HASHLINE_DATA_DIR/snapshots/v1/` (or the OS cache dir
182
- `hashline/snapshots/v1/` when `HASHLINE_DATA_DIR` is unset).
37
+ ## Commands
183
38
 
184
- ## MCP tool descriptions
39
+ - `read`: print a file with a `¶path#TAG` header and numbered lines
40
+ - `edit`: apply a hashline patch from stdin to files on disk
41
+ - `preview`: re-number a unified diff into a hashline-anchored compact preview
42
+ - `mcp`: start a stdio MCP server
185
43
 
186
- `hashline_read`:
187
- > Read a file and return its content tagged with a hashline header (¶path#TAG) followed
188
- > by numbered lines (N:LINE). Pass the returned header verbatim in hashline_edit patches
189
- > so the editor can verify the file has not changed since the read.
44
+ ## Documentation
190
45
 
191
- `hashline_edit`:
192
- > Apply a hashline patch to one or more files. Each section starts with a ¶path#TAG
193
- > header (obtained from hashline_read) followed by edit operations on the file's ORIGINAL
194
- > line numbers. Returns the new ¶path#TAG header per section so the next edit is grounded.
195
- > Returns IsError when the content tag is stale. Re-read the file first.
46
+ - [docs/install.md](docs/install.md): all install methods
47
+ - [docs/cli.md](docs/cli.md): full CLI reference (`read`, `edit`, `preview`, `mcp`)
48
+ - [docs/patch-format.md](docs/patch-format.md): patch sections and operations
49
+ - [docs/content-hash.md](docs/content-hash.md): CRC32 tag algorithm
50
+ - [docs/block-operations.md](docs/block-operations.md): tree-sitter `replace block` / `delete block`
51
+ - [docs/recovery.md](docs/recovery.md): stale-tag recovery and snapshot storage
52
+ - [docs/mcp.md](docs/mcp.md): MCP server, client config, and tool descriptions
196
53
 
197
54
  ## License
198
55
 
@@ -23,7 +23,7 @@
23
23
  "hasInstallScript": true,
24
24
  "license": "Apache-2.0",
25
25
  "name": "@skylence-ai/hashline",
26
- "version": "0.1.0"
26
+ "version": "0.1.1"
27
27
  },
28
28
  "node_modules/@isaacs/cliui": {
29
29
  "engines": {
@@ -542,5 +542,5 @@
542
542
  }
543
543
  },
544
544
  "requires": true,
545
- "version": "0.1.0"
545
+ "version": "0.1.1"
546
546
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "artifactDownloadUrls": [
3
- "https://github.com/skylence-be/hashline/releases/download/v0.1.0"
3
+ "https://github.com/skylence-be/hashline/releases/download/v0.1.1"
4
4
  ],
5
5
  "bin": {
6
6
  "hashline": "run-hashline.js"
@@ -84,7 +84,7 @@
84
84
  "zipExt": ".tar.xz"
85
85
  }
86
86
  },
87
- "version": "0.1.0",
87
+ "version": "0.1.1",
88
88
  "volta": {
89
89
  "node": "18.14.1",
90
90
  "npm": "9.5.0"