@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 +22 -165
- package/npm-shrinkwrap.json +2 -2
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
# hashline
|
|
2
2
|
|
|
3
|
+
[](https://www.npmjs.com/package/@skylence-ai/hashline)
|
|
4
|
+
[](https://github.com/skylence-be/hashline/actions/workflows/ci.yml)
|
|
5
|
+
[](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
|
-
##
|
|
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
|
-
|
|
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
|
-
|
|
55
|
-
#
|
|
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
|
-
##
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
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
|
|
package/npm-shrinkwrap.json
CHANGED
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
"hasInstallScript": true,
|
|
24
24
|
"license": "Apache-2.0",
|
|
25
25
|
"name": "@skylence-ai/hashline",
|
|
26
|
-
"version": "0.1.
|
|
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.
|
|
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.
|
|
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.
|
|
87
|
+
"version": "0.1.1",
|
|
88
88
|
"volta": {
|
|
89
89
|
"node": "18.14.1",
|
|
90
90
|
"npm": "9.5.0"
|