@levnikolaevich/hex-line-mcp 1.10.0 → 1.11.0

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
@@ -11,7 +11,7 @@ Every line carries an FNV-1a content hash. Every edit must present those hashes
11
11
 
12
12
  ## Features
13
13
 
14
- ### 10 MCP Tools
14
+ ### 9 MCP Tools
15
15
 
16
16
  Core day-to-day tools:
17
17
 
@@ -25,20 +25,18 @@ Core day-to-day tools:
25
25
  Advanced / occasional:
26
26
 
27
27
  - `write_file`
28
- - `directory_tree`
29
- - `get_file_info`
28
+ - `inspect_path`
30
29
  - `changes`
31
30
 
32
31
  | Tool | Description | Key Feature |
33
32
  |------|-------------|-------------|
34
- | `read_file` | Read file with hash-annotated lines, checksums, and revision | Partial reads via `offset`/`limit` or `ranges`, compact output by default |
33
+ | `read_file` | Read file with hash-annotated lines, checksums, revision, and automatic graph hints when available | Partial reads via `offset`/`limit` or `ranges`, compact output by default |
35
34
  | `edit_file` | Revision-aware anchor edits (`set_line`, `replace_lines`, `insert_after`, `replace_between`) | Batched same-file edits + conservative auto-rebase |
36
35
  | `write_file` | Create new file or overwrite, auto-creates parent dirs | Path validation, no hash overhead |
37
36
  | `grep_search` | Search with ripgrep, 3 output modes, per-group checksums | Plain `files`/`count`, compact edit-ready `content` |
38
- | `outline` | AST-based structural overview with hash anchors via tree-sitter WASM. Supports code (15+ langs) and fence-aware markdown headings | 95% token reduction, direct edit anchors |
37
+ | `outline` | AST-based structural overview with hash anchors via tree-sitter WASM. Supports JavaScript/TypeScript, Python, C#, PHP, and fence-aware markdown headings | 95% token reduction, direct edit anchors |
39
38
  | `verify` | Check if held checksums / revision are still current | Staleness check without full re-read |
40
- | `directory_tree` | Compact directory tree with root .gitignore support | Skips node_modules/.git, shows file sizes |
41
- | `get_file_info` | File metadata without reading content | Size, lines, mtime, type, binary detection |
39
+ | `inspect_path` | Unified file-or-directory inspection | File metadata for files, tree or pattern search for directories |
42
40
  | `changes` | Compare file against git ref, shows added/removed/modified symbols | AST-level semantic diff |
43
41
  | `bulk_replace` | Search-and-replace across multiple files by glob | Compact summary (default) or capped diffs via `format`, dry_run, max_files |
44
42
 
@@ -93,11 +91,12 @@ Comparative built-in vs hex-line benchmarks are maintained outside this package.
93
91
 
94
92
  ### Optional Graph Enrichment
95
93
 
96
- If a project already has `.hex-skills/codegraph/index.db`, `hex-line` can add lightweight graph hints to `read_file`, `outline`, `grep_search`, and `edit_file`.
94
+ If a project already has `.hex-skills/codegraph/index.db`, `hex-line` automatically adds lightweight graph hints to `read_file`, `outline`, `grep_search`, `edit_file`, and `changes`.
97
95
 
98
- - Graph enrichment is optional. If `.hex-skills/codegraph/index.db` is missing, `hex-line` falls back to standard behavior silently.
96
+ - Graph enrichment is optional. If `.hex-skills/codegraph/index.db` is missing, stale, or unreadable, `hex-line` falls back to standard behavior silently.
99
97
  - `better-sqlite3` is optional. If it is unavailable, `hex-line` still works without graph hints.
100
- - `edit_file` reports **Semantic impact** using explainable graph facts: external callers, downstream return/property flow, and clone peers when present.
98
+ - `read_file`, `outline`, and `grep_search` stay compact: they only surface high-signal local facts such as `api`, framework entrypoints, callers, flow, and clone hints.
99
+ - `edit_file` and `changes` surface the deeper review layer: external callers, downstream return/property flow, clone peers, public API risk, framework entrypoint risk, and same-name sibling warnings when present.
101
100
 
102
101
  `hex-line` does not read `hex-graph` internals directly anymore. The integration uses a small read-only contract exposed by `hex-graph-mcp`:
103
102
 
@@ -133,16 +132,15 @@ Use `bulk_replace` for text rename patterns across one or more files. Returns co
133
132
 
134
133
  ### read_file
135
134
 
136
- Read a file as canonical edit-ready blocks. Each valid range becomes a `read_range` block with absolute span, line entries, and a checksum covering exactly the emitted lines. Invalid ranges become explicit diagnostic blocks. Supports batch reads, multi-range reads, and directory listing.
135
+ Read a file as canonical edit-ready blocks. Each valid range becomes a `read_range` block with absolute span, line entries, and a checksum covering exactly the emitted lines. Invalid ranges become explicit diagnostic blocks. Supports batch reads and multi-range reads. Directories go through `inspect_path`.
137
136
 
138
137
  | Parameter | Type | Required | Description |
139
138
  |-----------|------|----------|-------------|
140
- | `path` | string | yes | File or directory path |
139
+ | `path` | string | yes | File path |
141
140
  | `paths` | string[] | no | Array of file paths to read (batch mode) |
142
141
  | `offset` | number | no | Start line, 1-indexed (default: 1) |
143
142
  | `limit` | number | no | Max lines to return (default: 2000, 0 = all) |
144
143
  | `ranges` | array | no | Explicit line ranges, e.g. `[{ "start": 10, "end": 30 }]` |
145
- | `include_graph` | boolean | no | Opt in to graph annotations when the graph index exists |
146
144
  | `plain` | boolean | no | Omit hashes, output `lineNum\|content` instead |
147
145
 
148
146
  Default output is compact but block-structured:
@@ -229,13 +227,13 @@ Search file contents using ripgrep. Three output modes: `content` (canonical `se
229
227
 
230
228
  ### outline
231
229
 
232
- AST-based structural outline with hash anchors for direct `edit_file` usage. Supports code files (15+ languages) and fence-aware markdown heading navigation (`.md`/`.mdx`). Each entry includes a hash tag for immediate anchor use without intermediate `read_file`.
230
+ AST-based structural outline with hash anchors for direct `edit_file` usage. Supports JavaScript/TypeScript, Python, C#, PHP, and fence-aware markdown heading navigation (`.md`/`.mdx`). Each entry includes a hash tag for immediate anchor use without intermediate `read_file`.
233
231
 
234
232
  | Parameter | Type | Required | Description |
235
233
  |-----------|------|----------|-------------|
236
234
  | `path` | string | yes | Source file path |
237
235
 
238
- Supported languages: JavaScript, TypeScript (JSX/TSX), Python, Go, Rust, Java, C, C++, C#, Ruby, PHP, Kotlin, Swift, Bash -- 15+ via tree-sitter WASM.
236
+ Supported languages: JavaScript (`.js`, `.mjs`, `.cjs`, `.jsx`), TypeScript (`.ts`, `.tsx`), Python (`.py`), C# (`.cs`), and PHP (`.php`) via tree-sitter WASM.
239
237
 
240
238
  Not for `.json`, `.yaml`, `.txt` -- use `read_file` directly for those.
241
239
 
@@ -262,30 +260,22 @@ changed_ranges: 10-12(replace)
262
260
  STALE 10-12 checksum: 10-12:oldc0de0 current=10-12:newc0de0
263
261
  ```
264
262
 
265
- ### directory_tree
263
+ ### inspect_path
266
264
 
267
- Compact directory tree with root .gitignore support (path-based rules, negation, dir-only). Nested .gitignore files are not loaded.
265
+ Inspect a file or directory path without guessing which low-level tool to call first.
268
266
 
269
267
  | Parameter | Type | Required | Description |
270
268
  |-----------|------|----------|-------------|
271
- | `path` | string | yes | Directory path |
269
+ | `path` | string | yes | File or directory path |
272
270
  | `pattern` | string | no | Glob filter on names (e.g. `"*-mcp"`, `"*.mjs"`). Returns flat match list instead of tree |
273
271
  | `type` | string | no | `"file"`, `"dir"`, or `"all"` (default). Like `find -type f/d` |
274
272
  | `max_depth` | number | no | Max recursion depth (default: 3, or 20 in pattern mode) |
275
273
  | `gitignore` | boolean | no | Respect root .gitignore patterns (default: true). Nested .gitignore not supported |
276
- | `format` | string | no | `"compact"` = names only, no sizes, depth 1. `"full"` = default with sizes |
277
-
278
- Skips `node_modules`, `.git`, `dist`, `build`, `__pycache__`, `.next`, `coverage` by default.
279
-
280
- ### get_file_info
281
-
282
- File metadata without reading content.
283
-
284
- | Parameter | Type | Required | Description |
285
- |-----------|------|----------|-------------|
286
- | `path` | string | yes | File path |
274
+ | `format` | string | no | `"compact"` = shorter path view. `"full"` = include sizes / metadata where available |
287
275
 
288
- Returns: size, line count, modification time (absolute + relative), file type, binary detection.
276
+ - For regular files it returns compact metadata: size, line count when cheap, modification time, type, and binary flag.
277
+ - For directories it returns a gitignore-aware tree.
278
+ - With `pattern`, it switches to flat match mode and works as the preferred replacement for `find` / recursive `ls`.
289
279
 
290
280
  ## Hook
291
281
 
@@ -324,11 +314,10 @@ Injects a short operational workflow into agent context at session start: no `To
324
314
 
325
315
  ```
326
316
  hex-line-mcp/
327
- server.mjs MCP server (stdio transport, 11 tools)
317
+ server.mjs MCP server (stdio transport, 9 tools)
328
318
  hook.mjs Unified hook (PreToolUse + PostToolUse + SessionStart)
329
319
  package.json
330
320
  lib/
331
- hash.mjs FNV-1a hashing, 2-char tags, range checksums
332
321
  read.mjs File reading with hash annotation
333
322
  edit.mjs Anchor-based edits, diff output
334
323
  search.mjs ripgrep wrapper with hash-annotated results
@@ -336,13 +325,15 @@ hex-line-mcp/
336
325
  verify.mjs Range checksum verification
337
326
  info.mjs File metadata (size, lines, mtime, type)
338
327
  tree.mjs Directory tree with .gitignore support
328
+ inspect-path.mjs Unified file/directory inspection
339
329
  changes.mjs Semantic git diff via AST
340
330
  bulk-replace.mjs Multi-file search-and-replace
341
331
  setup.mjs Claude hook installation + output style setup
342
332
  format.mjs Output formatting utilities
343
- coerce.mjs Parameter pass-through (identity)
344
333
  security.mjs Path validation, binary detection, size limits
345
- normalize.mjs Output normalization, deduplication, truncation
334
+ @levnikolaevich/hex-common/
335
+ text-protocol/hash.mjs Shared FNV-1a hashing and checksum protocol
336
+ output/normalize.mjs Shared output normalization helpers
346
337
  ```
347
338
 
348
339
  ### Hash Format
@@ -392,7 +383,7 @@ The edit is rejected with an error showing which lines changed since the last re
392
383
  <details>
393
384
  <summary><b>Is outline available for all file types?</b></summary>
394
385
 
395
- Outline works on code files (15+ languages via tree-sitter WASM) and markdown heading navigation (`.md`/`.mdx`, fenced code blocks ignored). For JSON, YAML, and text files use `read_file` directly. Each outline entry includes a hash anchor (`tag.line-range: symbol`) for direct use in `edit_file`.
386
+ Outline works on JavaScript/TypeScript, Python, C#, PHP, and markdown heading navigation (`.md`/`.mdx`, fenced code blocks ignored). For JSON, YAML, and text files use `read_file` directly. Each outline entry includes a hash anchor (`tag.line-range: symbol`) for direct use in `edit_file`.
396
387
 
397
388
  </details>
398
389
 
@@ -0,0 +1,57 @@
1
+ {
2
+ "generated_from": {
3
+ "source": "tree-sitter-cli-build",
4
+ "tree_sitter_cli_version": "0.26.8",
5
+ "note": "Repo-owned grammar WASM artifacts built from pinned npm grammar packages with the current tree-sitter CLI."
6
+ },
7
+ "grammars": [
8
+ {
9
+ "grammar": "javascript",
10
+ "file": "tree-sitter-javascript.wasm",
11
+ "package": "tree-sitter-javascript",
12
+ "version": "0.25.0",
13
+ "source_subdir": null,
14
+ "sha256": "29d37c59b7797fa1c56419816d1730d5ff5e2ed2077bc44c5d6f50082be09136"
15
+ },
16
+ {
17
+ "grammar": "typescript",
18
+ "file": "tree-sitter-typescript.wasm",
19
+ "package": "tree-sitter-typescript",
20
+ "version": "0.23.2",
21
+ "source_subdir": "typescript",
22
+ "sha256": "f7c442260d8bf63b89762af2663655d153f84d169b4b8fedd15a5ba9b29ed3a4"
23
+ },
24
+ {
25
+ "grammar": "tsx",
26
+ "file": "tree-sitter-tsx.wasm",
27
+ "package": "tree-sitter-typescript",
28
+ "version": "0.23.2",
29
+ "source_subdir": "tsx",
30
+ "sha256": "4f795eb1fd00d14b7d284add59df8796d3c4b30e49d27979cba70c02298d5f67"
31
+ },
32
+ {
33
+ "grammar": "python",
34
+ "file": "tree-sitter-python.wasm",
35
+ "package": "tree-sitter-python",
36
+ "version": "0.25.0",
37
+ "source_subdir": null,
38
+ "sha256": "6183aa51eecace847badb487766e33a0f7725c257b479a0b89c9ff1bcec9c610"
39
+ },
40
+ {
41
+ "grammar": "c_sharp",
42
+ "file": "tree-sitter-c_sharp.wasm",
43
+ "package": "tree-sitter-c-sharp",
44
+ "version": "0.23.1",
45
+ "source_subdir": null,
46
+ "sha256": "974cb3e3302c04a5b5e6734494af2ed2fd0c284c38693316ef013922639aecf2"
47
+ },
48
+ {
49
+ "grammar": "php",
50
+ "file": "tree-sitter-php.wasm",
51
+ "package": "tree-sitter-php",
52
+ "version": "0.24.2",
53
+ "source_subdir": "php",
54
+ "sha256": "393e65be27e256ed2f1a43e0e70e43de05f77b5563d7dd877bdb44760d5560a6"
55
+ }
56
+ ]
57
+ }
package/dist/hook.mjs CHANGED
@@ -97,27 +97,15 @@ var OUTLINEABLE_EXT = /* @__PURE__ */ new Set([
97
97
  ".ts",
98
98
  ".tsx",
99
99
  ".py",
100
- ".go",
101
- ".rs",
102
- ".java",
103
- ".c",
104
- ".h",
105
- ".cpp",
106
100
  ".cs",
107
- ".rb",
108
- ".php",
109
- ".kt",
110
- ".swift",
111
- ".sh",
112
- ".bash"
101
+ ".php"
113
102
  ]);
114
103
  var REVERSE_TOOL_HINTS = {
115
104
  "mcp__hex-line__read_file": "Read (file_path, offset, limit)",
116
105
  "mcp__hex-line__edit_file": "Edit (old_string, new_string, replace_all)",
117
106
  "mcp__hex-line__write_file": "Write (file_path, content)",
118
107
  "mcp__hex-line__grep_search": "Grep (pattern, path)",
119
- "mcp__hex-line__directory_tree": "Glob (pattern) or Bash(ls)",
120
- "mcp__hex-line__get_file_info": "Bash(stat/wc)",
108
+ "mcp__hex-line__inspect_path": "Path info / tree / Bash(ls,stat)",
121
109
  "mcp__hex-line__outline": "Read with offset/limit",
122
110
  "mcp__hex-line__verify": "Read (re-read file to check freshness)",
123
111
  "mcp__hex-line__changes": "Bash(git diff)",
@@ -131,8 +119,8 @@ var TOOL_HINTS = {
131
119
  cat: "mcp__hex-line__read_file (not cat/head/tail/less/more)",
132
120
  head: "mcp__hex-line__read_file with limit param (not head)",
133
121
  tail: "mcp__hex-line__read_file with offset param (not tail)",
134
- ls: "mcp__hex-line__directory_tree with pattern param (not ls/find/tree). E.g. pattern='*-mcp' type='dir'",
135
- stat: "mcp__hex-line__get_file_info (not stat/wc/file)",
122
+ ls: "mcp__hex-line__inspect_path for tree or pattern search (not ls/find/tree). E.g. pattern='*-mcp' type='dir'",
123
+ stat: "mcp__hex-line__inspect_path for compact file metadata (not stat/wc/file)",
136
124
  grep: "mcp__hex-line__grep_search (not grep/rg). Params: output, literal, context_before, context_after, multiline",
137
125
  sed: "mcp__hex-line__edit_file for hash edits, or mcp__hex-line__bulk_replace for text rename (not sed -i)",
138
126
  diff: "mcp__hex-line__changes (not diff). Git diff with change symbols",
@@ -358,7 +346,7 @@ function handlePreToolUse(data) {
358
346
  advise(hint, DEFERRED_HINT);
359
347
  }
360
348
  const ext = filePath ? extOf(filePath) : "";
361
- const outlineHint = filePath && OUTLINEABLE_EXT.has(ext) ? `Use mcp__hex-line__outline(path="${filePath}") for structure, then mcp__hex-line__read_file(path="${filePath}") with ranges to read only what you need.` : filePath ? `Use mcp__hex-line__read_file(path="${filePath}") with ranges or offset/limit` : "Use mcp__hex-line__directory_tree or mcp__hex-line__read_file";
349
+ const outlineHint = filePath && OUTLINEABLE_EXT.has(ext) ? `Use mcp__hex-line__outline(path="${filePath}") for structure, then mcp__hex-line__read_file(path="${filePath}") with ranges to read only what you need.` : filePath ? `Use mcp__hex-line__read_file(path="${filePath}") with ranges or offset/limit` : "Use mcp__hex-line__inspect_path or mcp__hex-line__read_file";
362
350
  redirect(outlineHint, "Do not use built-in Read for full reads of large files.\n" + DEFERRED_HINT);
363
351
  }
364
352
  if (toolName === "Edit") {