@levnikolaevich/hex-line-mcp 1.7.0 → 1.8.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 +3 -19
- package/dist/hook.mjs +33 -9
- package/dist/server.mjs +52 -115
- package/output-style.md +16 -1
- package/package.json +2 -2
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
|
-
###
|
|
14
|
+
### 10 MCP Tools
|
|
15
15
|
|
|
16
16
|
Core day-to-day tools:
|
|
17
17
|
|
|
@@ -28,7 +28,6 @@ Advanced / occasional:
|
|
|
28
28
|
- `directory_tree`
|
|
29
29
|
- `get_file_info`
|
|
30
30
|
- `changes`
|
|
31
|
-
- `setup_hooks`
|
|
32
31
|
|
|
33
32
|
| Tool | Description | Key Feature |
|
|
34
33
|
|------|-------------|-------------|
|
|
@@ -40,7 +39,6 @@ Advanced / occasional:
|
|
|
40
39
|
| `verify` | Check if held checksums / revision are still current | Staleness check without full re-read |
|
|
41
40
|
| `directory_tree` | Compact directory tree with root .gitignore support | Skips node_modules/.git, shows file sizes |
|
|
42
41
|
| `get_file_info` | File metadata without reading content | Size, lines, mtime, type, binary detection |
|
|
43
|
-
| `setup_hooks` | Configure Claude hooks + install output style | Gemini/Codex get guidance only; no hooks |
|
|
44
42
|
| `changes` | Compare file against git ref, shows added/removed/modified symbols | AST-level semantic diff |
|
|
45
43
|
| `bulk_replace` | Search-and-replace across multiple files by glob | Compact summary (default) or capped diffs via `format`, dry_run, max_files |
|
|
46
44
|
|
|
@@ -70,23 +68,9 @@ ripgrep is bundled via `@vscode/ripgrep` — no manual install needed for `grep_
|
|
|
70
68
|
|
|
71
69
|
### Hooks
|
|
72
70
|
|
|
73
|
-
|
|
71
|
+
Hooks and output style are auto-synced on every MCP server startup. The server compares installed files with bundled versions and updates only when content differs. First run after `npm i -g` triggers full install automatically.
|
|
74
72
|
|
|
75
|
-
|
|
76
|
-
mcp__hex-line__setup_hooks(agent="claude")
|
|
77
|
-
```
|
|
78
|
-
|
|
79
|
-
Hooks are written to global `~/.claude/settings.json` with absolute path to `hook.mjs` from the global npm install. Manual configuration is not needed.
|
|
80
|
-
|
|
81
|
-
### Output Style
|
|
82
|
-
|
|
83
|
-
Optional: install a persistent Output Style that embeds tool preferences directly in Claude's system prompt. Reduces hook firings by making Claude prefer hex-line tools from the start.
|
|
84
|
-
|
|
85
|
-
```
|
|
86
|
-
mcp__hex-line__setup_hooks(agent="claude")
|
|
87
|
-
```
|
|
88
|
-
|
|
89
|
-
The `setup_hooks` tool automatically installs the output style to `~/.claude/output-styles/hex-line.md` and activates it if no other style is set. To activate manually: `/config` > Output style > hex-line.
|
|
73
|
+
Hooks are written to global `~/.claude/settings.json` with absolute path to `hook.mjs`. Output style is installed to `~/.claude/output-styles/hex-line.md` and activated if no other style is set. To activate manually: `/config` > Output style > hex-line.
|
|
90
74
|
|
|
91
75
|
## Validation
|
|
92
76
|
|
package/dist/hook.mjs
CHANGED
|
@@ -89,6 +89,28 @@ var BINARY_EXT = /* @__PURE__ */ new Set([
|
|
|
89
89
|
".woff",
|
|
90
90
|
".woff2"
|
|
91
91
|
]);
|
|
92
|
+
var OUTLINEABLE_EXT = /* @__PURE__ */ new Set([
|
|
93
|
+
".js",
|
|
94
|
+
".mjs",
|
|
95
|
+
".cjs",
|
|
96
|
+
".jsx",
|
|
97
|
+
".ts",
|
|
98
|
+
".tsx",
|
|
99
|
+
".py",
|
|
100
|
+
".go",
|
|
101
|
+
".rs",
|
|
102
|
+
".java",
|
|
103
|
+
".c",
|
|
104
|
+
".h",
|
|
105
|
+
".cpp",
|
|
106
|
+
".cs",
|
|
107
|
+
".rb",
|
|
108
|
+
".php",
|
|
109
|
+
".kt",
|
|
110
|
+
".swift",
|
|
111
|
+
".sh",
|
|
112
|
+
".bash"
|
|
113
|
+
]);
|
|
92
114
|
var REVERSE_TOOL_HINTS = {
|
|
93
115
|
"mcp__hex-line__read_file": "Read (file_path, offset, limit)",
|
|
94
116
|
"mcp__hex-line__edit_file": "Edit (old_string, new_string, replace_all)",
|
|
@@ -99,8 +121,7 @@ var REVERSE_TOOL_HINTS = {
|
|
|
99
121
|
"mcp__hex-line__outline": "Read with offset/limit",
|
|
100
122
|
"mcp__hex-line__verify": "Read (re-read file to check freshness)",
|
|
101
123
|
"mcp__hex-line__changes": "Bash(git diff)",
|
|
102
|
-
"mcp__hex-line__bulk_replace": "Edit (text rename/refactor across files)"
|
|
103
|
-
"mcp__hex-line__setup_hooks": "Not available (hex-line disabled)"
|
|
124
|
+
"mcp__hex-line__bulk_replace": "Edit (text rename/refactor across files)"
|
|
104
125
|
};
|
|
105
126
|
var TOOL_HINTS = {
|
|
106
127
|
Read: "mcp__hex-line__read_file (not Read). For writing: write_file (no prior Read needed)",
|
|
@@ -118,8 +139,7 @@ var TOOL_HINTS = {
|
|
|
118
139
|
outline: "mcp__hex-line__outline (before reading large code files)",
|
|
119
140
|
verify: "mcp__hex-line__verify (staleness / revision check without re-read)",
|
|
120
141
|
changes: "mcp__hex-line__changes (git diff with change symbols)",
|
|
121
|
-
bulk: "mcp__hex-line__bulk_replace (multi-file search-replace)"
|
|
122
|
-
setup: "mcp__hex-line__setup_hooks (configure hooks for agents)"
|
|
142
|
+
bulk: "mcp__hex-line__bulk_replace (multi-file search-replace)"
|
|
123
143
|
};
|
|
124
144
|
var BASH_REDIRECTS = [
|
|
125
145
|
{ regex: /^cat\s+\S+/, key: "cat" },
|
|
@@ -183,7 +203,7 @@ var CMD_PATTERNS = [
|
|
|
183
203
|
var LINE_THRESHOLD = 50;
|
|
184
204
|
var HEAD_LINES = 15;
|
|
185
205
|
var TAIL_LINES = 15;
|
|
186
|
-
var LARGE_FILE_BYTES =
|
|
206
|
+
var LARGE_FILE_BYTES = 5 * 1024;
|
|
187
207
|
var LARGE_EDIT_CHARS = 1200;
|
|
188
208
|
function extOf(filePath) {
|
|
189
209
|
const dot = filePath.lastIndexOf(".");
|
|
@@ -328,10 +348,13 @@ function handlePreToolUse(data) {
|
|
|
328
348
|
process.exit(0);
|
|
329
349
|
}
|
|
330
350
|
if (fileSize !== null && fileSize <= LARGE_FILE_BYTES) {
|
|
331
|
-
|
|
351
|
+
const ext2 = filePath ? extOf(filePath) : "";
|
|
352
|
+
const hint = filePath && OUTLINEABLE_EXT.has(ext2) ? `mcp__hex-line__outline(path="${filePath}") gives a compact structural map. For edits, use mcp__hex-line__read_file(path="${filePath}") with ranges.` : filePath ? `NEXT READ: use mcp__hex-line__read_file(path="${filePath}"). Built-in Read allowed this time but wastes edit context.` : "NEXT READ: use mcp__hex-line__read_file. Built-in Read allowed this time but wastes edit context.";
|
|
353
|
+
advise(hint);
|
|
332
354
|
}
|
|
333
|
-
const
|
|
334
|
-
|
|
355
|
+
const ext = filePath ? extOf(filePath) : "";
|
|
356
|
+
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";
|
|
357
|
+
redirect(outlineHint, "Do not use built-in Read for full reads of large files.");
|
|
335
358
|
}
|
|
336
359
|
if (toolName === "Edit") {
|
|
337
360
|
const oldText = String(toolInput.old_string || "");
|
|
@@ -460,7 +483,8 @@ function handleSessionStart() {
|
|
|
460
483
|
process.stdout.write(JSON.stringify({ systemMessage: msg }));
|
|
461
484
|
process.exit(0);
|
|
462
485
|
}
|
|
463
|
-
|
|
486
|
+
var _norm = (p) => p.replace(/\\/g, "/");
|
|
487
|
+
if (_norm(process.argv[1]) === _norm(fileURLToPath(import.meta.url))) {
|
|
464
488
|
let input = "";
|
|
465
489
|
process.stdin.on("data", (chunk) => {
|
|
466
490
|
input += chunk;
|
package/dist/server.mjs
CHANGED
|
@@ -483,7 +483,7 @@ function parseChecksum(cs) {
|
|
|
483
483
|
// lib/snapshot.mjs
|
|
484
484
|
var MAX_FILES = 200;
|
|
485
485
|
var MAX_REVISIONS_PER_FILE = 5;
|
|
486
|
-
var TTL_MS =
|
|
486
|
+
var TTL_MS = 15 * 60 * 1e3;
|
|
487
487
|
var latestByFile = /* @__PURE__ */ new Map();
|
|
488
488
|
var revisionsById = /* @__PURE__ */ new Map();
|
|
489
489
|
var fileRevisionIds = /* @__PURE__ */ new Map();
|
|
@@ -2425,6 +2425,8 @@ var __filename = fileURLToPath(import.meta.url);
|
|
|
2425
2425
|
var __dirname = dirname3(__filename);
|
|
2426
2426
|
var SOURCE_HOOK = resolve6(__dirname, "..", "hook.mjs");
|
|
2427
2427
|
var DIST_HOOK = resolve6(__dirname, "hook.mjs");
|
|
2428
|
+
var SOURCE_STYLE = resolve6(__dirname, "..", "output-style.md");
|
|
2429
|
+
var INSTALLED_STYLE = resolve6(homedir(), ".claude", "output-styles", "hex-line.md");
|
|
2428
2430
|
var HOOK_SIGNATURE = "hex-line";
|
|
2429
2431
|
var CLAUDE_HOOKS = {
|
|
2430
2432
|
SessionStart: {
|
|
@@ -2455,16 +2457,19 @@ function findEntryByCommand(entries) {
|
|
|
2455
2457
|
)
|
|
2456
2458
|
);
|
|
2457
2459
|
}
|
|
2458
|
-
function
|
|
2459
|
-
|
|
2460
|
-
|
|
2461
|
-
|
|
2460
|
+
function safeRead(filePath) {
|
|
2461
|
+
try {
|
|
2462
|
+
return readFileSync3(filePath, "utf-8");
|
|
2463
|
+
} catch {
|
|
2464
|
+
return null;
|
|
2462
2465
|
}
|
|
2466
|
+
}
|
|
2467
|
+
function writeHooksToFile(settingsPath) {
|
|
2468
|
+
const config = readJson(settingsPath) || {};
|
|
2469
|
+
if (!config.hooks || typeof config.hooks !== "object") config.hooks = {};
|
|
2463
2470
|
let changed = false;
|
|
2464
2471
|
for (const [event, desired] of Object.entries(CLAUDE_HOOKS)) {
|
|
2465
|
-
if (!Array.isArray(config.hooks[event]))
|
|
2466
|
-
config.hooks[event] = [];
|
|
2467
|
-
}
|
|
2472
|
+
if (!Array.isArray(config.hooks[event])) config.hooks[event] = [];
|
|
2468
2473
|
const entries = config.hooks[event];
|
|
2469
2474
|
const idx = findEntryByCommand(entries);
|
|
2470
2475
|
if (idx >= 0) {
|
|
@@ -2483,116 +2488,60 @@ function writeHooksToFile(settingsPath, label) {
|
|
|
2483
2488
|
config.disableAllHooks = false;
|
|
2484
2489
|
changed = true;
|
|
2485
2490
|
}
|
|
2486
|
-
if (
|
|
2487
|
-
|
|
2488
|
-
}
|
|
2489
|
-
writeJson(settingsPath, config);
|
|
2490
|
-
return `Claude (${label}): hooks -> ${STABLE_HOOK_PATH} OK`;
|
|
2491
|
+
if (changed) writeJson(settingsPath, config);
|
|
2492
|
+
return changed;
|
|
2491
2493
|
}
|
|
2492
2494
|
function cleanLocalHooks() {
|
|
2493
2495
|
const localPath = resolve6(process.cwd(), ".claude/settings.local.json");
|
|
2494
2496
|
const config = readJson(localPath);
|
|
2495
|
-
if (!config || !config.hooks || typeof config.hooks !== "object")
|
|
2496
|
-
return "local: clean";
|
|
2497
|
-
}
|
|
2497
|
+
if (!config || !config.hooks || typeof config.hooks !== "object") return;
|
|
2498
2498
|
let changed = false;
|
|
2499
2499
|
for (const event of Object.keys(CLAUDE_HOOKS)) {
|
|
2500
2500
|
if (!Array.isArray(config.hooks[event])) continue;
|
|
2501
|
-
const
|
|
2502
|
-
const idx = findEntryByCommand(entries);
|
|
2501
|
+
const idx = findEntryByCommand(config.hooks[event]);
|
|
2503
2502
|
if (idx >= 0) {
|
|
2504
|
-
|
|
2503
|
+
config.hooks[event].splice(idx, 1);
|
|
2505
2504
|
changed = true;
|
|
2506
2505
|
}
|
|
2507
|
-
if (
|
|
2508
|
-
delete config.hooks[event];
|
|
2509
|
-
}
|
|
2510
|
-
}
|
|
2511
|
-
if (Object.keys(config.hooks).length === 0) {
|
|
2512
|
-
delete config.hooks;
|
|
2506
|
+
if (config.hooks[event].length === 0) delete config.hooks[event];
|
|
2513
2507
|
}
|
|
2514
|
-
if (
|
|
2515
|
-
|
|
2516
|
-
|
|
2517
|
-
|
|
2518
|
-
|
|
2519
|
-
|
|
2520
|
-
|
|
2521
|
-
|
|
2522
|
-
|
|
2523
|
-
|
|
2524
|
-
writeFileSync2(target, readFileSync3(source, "utf-8"), "utf-8");
|
|
2508
|
+
if (Object.keys(config.hooks).length === 0) delete config.hooks;
|
|
2509
|
+
if (changed) writeJson(localPath, config);
|
|
2510
|
+
}
|
|
2511
|
+
function syncOutputStyle() {
|
|
2512
|
+
const source = safeRead(SOURCE_STYLE);
|
|
2513
|
+
if (!source) return false;
|
|
2514
|
+
const installed = safeRead(INSTALLED_STYLE);
|
|
2515
|
+
if (installed === source) return false;
|
|
2516
|
+
mkdirSync(dirname3(INSTALLED_STYLE), { recursive: true });
|
|
2517
|
+
writeFileSync2(INSTALLED_STYLE, source, "utf-8");
|
|
2525
2518
|
const userSettings = resolve6(homedir(), ".claude/settings.json");
|
|
2526
2519
|
const config = readJson(userSettings) || {};
|
|
2527
|
-
|
|
2528
|
-
if (!prev) {
|
|
2520
|
+
if (!config.outputStyle) {
|
|
2529
2521
|
config.outputStyle = "hex-line";
|
|
2530
2522
|
writeJson(userSettings, config);
|
|
2531
2523
|
}
|
|
2532
|
-
|
|
2533
|
-
return msg;
|
|
2524
|
+
return true;
|
|
2534
2525
|
}
|
|
2535
|
-
function
|
|
2536
|
-
const results = [];
|
|
2526
|
+
function autoSync() {
|
|
2537
2527
|
const hookSource = existsSync5(DIST_HOOK) ? DIST_HOOK : SOURCE_HOOK;
|
|
2538
|
-
if (!existsSync5(hookSource))
|
|
2539
|
-
|
|
2540
|
-
|
|
2541
|
-
|
|
2542
|
-
|
|
2543
|
-
|
|
2544
|
-
|
|
2545
|
-
|
|
2546
|
-
|
|
2547
|
-
|
|
2548
|
-
return results.join(" | ");
|
|
2549
|
-
}
|
|
2550
|
-
function setupGemini() {
|
|
2551
|
-
return "Gemini: Not supported (Gemini CLI does not support hooks. Add MCP Tool Preferences to GEMINI.md instead)";
|
|
2552
|
-
}
|
|
2553
|
-
function setupCodex() {
|
|
2554
|
-
return "Codex: Not supported (Codex CLI does not support hooks. Add MCP Tool Preferences to AGENTS.md instead)";
|
|
2555
|
-
}
|
|
2556
|
-
function uninstallClaude() {
|
|
2528
|
+
if (!existsSync5(hookSource)) return;
|
|
2529
|
+
const changes = [];
|
|
2530
|
+
const srcHook = safeRead(hookSource);
|
|
2531
|
+
const dstHook = safeRead(STABLE_HOOK_PATH);
|
|
2532
|
+
if (srcHook && srcHook !== dstHook) {
|
|
2533
|
+
mkdirSync(STABLE_HOOK_DIR, { recursive: true });
|
|
2534
|
+
copyFileSync(hookSource, STABLE_HOOK_PATH);
|
|
2535
|
+
changes.push("hook");
|
|
2536
|
+
}
|
|
2537
|
+
if (syncOutputStyle()) changes.push("style");
|
|
2557
2538
|
const globalPath = resolve6(homedir(), ".claude/settings.json");
|
|
2558
|
-
|
|
2559
|
-
|
|
2560
|
-
|
|
2561
|
-
|
|
2562
|
-
|
|
2563
|
-
for (const event of Object.keys(CLAUDE_HOOKS)) {
|
|
2564
|
-
if (!Array.isArray(config.hooks[event])) continue;
|
|
2565
|
-
const idx = findEntryByCommand(config.hooks[event]);
|
|
2566
|
-
if (idx >= 0) {
|
|
2567
|
-
config.hooks[event].splice(idx, 1);
|
|
2568
|
-
if (config.hooks[event].length === 0) delete config.hooks[event];
|
|
2569
|
-
changed = true;
|
|
2570
|
-
}
|
|
2571
|
-
}
|
|
2572
|
-
if (Object.keys(config.hooks).length === 0) delete config.hooks;
|
|
2573
|
-
if (!changed) return "Claude: no hex-line hooks found";
|
|
2574
|
-
writeJson(globalPath, config);
|
|
2575
|
-
return "Claude: hex-line hooks removed from global settings";
|
|
2576
|
-
}
|
|
2577
|
-
var AGENTS = { claude: setupClaude, gemini: setupGemini, codex: setupCodex };
|
|
2578
|
-
function setupHooks(agent = "all", action = "install") {
|
|
2579
|
-
const target = (agent || "all").toLowerCase();
|
|
2580
|
-
const act = (action || "install").toLowerCase();
|
|
2581
|
-
if (act === "uninstall") {
|
|
2582
|
-
const result = uninstallClaude();
|
|
2583
|
-
return `Hooks uninstalled:
|
|
2584
|
-
${result}
|
|
2585
|
-
|
|
2586
|
-
Restart Claude Code to apply changes.`;
|
|
2587
|
-
}
|
|
2588
|
-
if (target !== "all" && !AGENTS[target]) {
|
|
2589
|
-
throw new Error(`UNKNOWN_AGENT: '${agent}'. Supported: claude, gemini, codex, all`);
|
|
2539
|
+
if (writeHooksToFile(globalPath)) changes.push("settings");
|
|
2540
|
+
cleanLocalHooks();
|
|
2541
|
+
if (changes.length > 0) {
|
|
2542
|
+
process.stderr.write(`hex-line: synced ${changes.join(", ")}
|
|
2543
|
+
`);
|
|
2590
2544
|
}
|
|
2591
|
-
const targets = target === "all" ? Object.keys(AGENTS) : [target];
|
|
2592
|
-
const results = targets.map((name) => " " + AGENTS[name]());
|
|
2593
|
-
const header = `Hooks configured for ${target}:`;
|
|
2594
|
-
const footer = "\nRestart Claude Code to apply hook changes.";
|
|
2595
|
-
return [header, ...results, footer].join("\n");
|
|
2596
2545
|
}
|
|
2597
2546
|
|
|
2598
2547
|
// lib/changes.mjs
|
|
@@ -2837,7 +2786,7 @@ OUTPUT_CAPPED: Output exceeded ${MAX_BULK_OUTPUT_CHARS} chars.`;
|
|
|
2837
2786
|
}
|
|
2838
2787
|
|
|
2839
2788
|
// server.mjs
|
|
2840
|
-
var version = true ? "1.
|
|
2789
|
+
var version = true ? "1.8.0" : (await null).createRequire(import.meta.url)("./package.json").version;
|
|
2841
2790
|
var { server, StdioServerTransport } = await createServerRuntime({
|
|
2842
2791
|
name: "hex-line-mcp",
|
|
2843
2792
|
version
|
|
@@ -3086,22 +3035,6 @@ server.registerTool("get_file_info", {
|
|
|
3086
3035
|
return { content: [{ type: "text", text: e.message }], isError: true };
|
|
3087
3036
|
}
|
|
3088
3037
|
});
|
|
3089
|
-
server.registerTool("setup_hooks", {
|
|
3090
|
-
title: "Setup Hooks",
|
|
3091
|
-
description: "Install or uninstall hex-line hooks in CLI agent settings. Idempotent.",
|
|
3092
|
-
inputSchema: z2.object({
|
|
3093
|
-
agent: z2.string().optional().describe('Target agent: "claude", "gemini", "codex", or "all" (default: "all")'),
|
|
3094
|
-
action: z2.string().optional().describe('"install" (default) or "uninstall"')
|
|
3095
|
-
}),
|
|
3096
|
-
annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: true }
|
|
3097
|
-
}, async (rawParams) => {
|
|
3098
|
-
const { agent, action } = coerceParams(rawParams);
|
|
3099
|
-
try {
|
|
3100
|
-
return { content: [{ type: "text", text: setupHooks(agent, action) }] };
|
|
3101
|
-
} catch (e) {
|
|
3102
|
-
return { content: [{ type: "text", text: e.message }], isError: true };
|
|
3103
|
-
}
|
|
3104
|
-
});
|
|
3105
3038
|
server.registerTool("changes", {
|
|
3106
3039
|
title: "Semantic Diff",
|
|
3107
3040
|
description: "Compare file or directory against git ref (default: HEAD). Shows added/removed/modified symbols or file stats.",
|
|
@@ -3155,3 +3088,7 @@ server.registerTool("bulk_replace", {
|
|
|
3155
3088
|
var transport = new StdioServerTransport();
|
|
3156
3089
|
await server.connect(transport);
|
|
3157
3090
|
void checkForUpdates("@levnikolaevich/hex-line-mcp", version);
|
|
3091
|
+
try {
|
|
3092
|
+
autoSync();
|
|
3093
|
+
} catch {
|
|
3094
|
+
}
|
package/output-style.md
CHANGED
|
@@ -36,7 +36,8 @@ Prefer:
|
|
|
36
36
|
2. send one `edit_file` call with batched edits
|
|
37
37
|
3. carry `revision` from `read_file` into `base_revision` on follow-up edits
|
|
38
38
|
4. use `set_line`, `replace_lines`, `insert_after`, `replace_between` based on scope
|
|
39
|
-
5.
|
|
39
|
+
5. if edit returns CONFLICT, call `verify` with stale checksum — it reports VALID/STALE/INVALID without rereading the whole file
|
|
40
|
+
6. only reread (`read_file`) when `verify` confirms STALE
|
|
40
41
|
|
|
41
42
|
Post-edit output uses `block: post_edit` with checksum — use it directly for follow-up edits or verify.
|
|
42
43
|
|
|
@@ -45,6 +46,20 @@ Avoid:
|
|
|
45
46
|
- full-file rewrites for local changes
|
|
46
47
|
- using `bulk_replace` for structural block rewrites
|
|
47
48
|
|
|
49
|
+
|
|
50
|
+
## hex-graph — Code Analysis
|
|
51
|
+
|
|
52
|
+
Run `index_project` once per session before using other graph tools.
|
|
53
|
+
|
|
54
|
+
| Task | Tool | Output |
|
|
55
|
+
|------|------|--------|
|
|
56
|
+
| Refactoring / moving code | `find_references`, `find_implementations` | All usages + implementations |
|
|
57
|
+
| Code review / tech debt | `find_cycles`, `find_hotspots` | Circular deps, complexity hotspots |
|
|
58
|
+
| Dead code cleanup | `find_unused_exports` | Exports nobody imports |
|
|
59
|
+
| Architecture overview | `get_architecture`, `get_module_metrics` | Module map + coupling metrics |
|
|
60
|
+
| Duplicate detection | `find_clones` | Similar code blocks |
|
|
61
|
+
| Impact analysis | `trace_paths` | Call chains A → B |
|
|
62
|
+
| Symbol lookup | `search_symbols`, `get_symbol` | Find by name, get details |
|
|
48
63
|
# Response Style
|
|
49
64
|
|
|
50
65
|
Keep responses compact and operational. Explain only what is needed to complete the task or justify a non-obvious decision.
|
package/package.json
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@levnikolaevich/hex-line-mcp",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.8.0",
|
|
4
4
|
"mcpName": "io.github.levnikolaevich/hex-line-mcp",
|
|
5
5
|
"type": "module",
|
|
6
|
-
"description": "Hash-verified file editing MCP + token efficiency hook for AI coding agents.
|
|
6
|
+
"description": "Hash-verified file editing MCP + token efficiency hook for AI coding agents. 10 tools: read, edit, write, grep, outline, verify, directory_tree, file_info, changes, bulk_replace.",
|
|
7
7
|
"main": "dist/server.mjs",
|
|
8
8
|
"bin": {
|
|
9
9
|
"hex-line-mcp": "dist/server.mjs"
|