@levnikolaevich/hex-line-mcp 1.8.0 → 1.9.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.
Files changed (2) hide show
  1. package/dist/server.mjs +65 -5
  2. package/package.json +1 -1
package/dist/server.mjs CHANGED
@@ -281,7 +281,7 @@ function validateWritePath(filePath) {
281
281
  import { existsSync as existsSync2 } from "node:fs";
282
282
  import { join as join3, dirname as dirname2, relative } from "node:path";
283
283
  import { createRequire } from "node:module";
284
- var HEX_LINE_CONTRACT_VERSION = 1;
284
+ var HEX_LINE_CONTRACT_VERSION = 2;
285
285
  var _dbs = /* @__PURE__ */ new Map();
286
286
  var _driverUnavailable = false;
287
287
  function getGraphDB(filePath) {
@@ -311,7 +311,7 @@ function validateHexLineContract(db) {
311
311
  const contract = db.prepare("SELECT contract_version FROM hex_line_contract LIMIT 1").get();
312
312
  if (!contract || contract.contract_version !== HEX_LINE_CONTRACT_VERSION) return false;
313
313
  db.prepare("SELECT node_id, file, line_start, line_end, display_name, kind, callees, callers FROM hex_line_symbol_annotations LIMIT 1").all();
314
- db.prepare("SELECT source_id, target_id, source_file, source_line, source_display_name, target_file, target_line, target_display_name FROM hex_line_call_edges LIMIT 1").all();
314
+ db.prepare("SELECT source_id, target_id, source_file, source_line, source_display_name, target_file, target_line, target_display_name, confidence FROM hex_line_call_edges LIMIT 1").all();
315
315
  return true;
316
316
  } catch {
317
317
  return false;
@@ -363,7 +363,8 @@ function callImpact(db, file, startLine, endLine) {
363
363
  const dependents = db.prepare(
364
364
  `SELECT source_display_name AS name, source_file AS file, source_line AS line
365
365
  FROM hex_line_call_edges
366
- WHERE target_id = ?`
366
+ WHERE target_id = ?
367
+ AND confidence IN ('exact', 'precise')`
367
368
  ).all(node.node_id);
368
369
  for (const dep of dependents) {
369
370
  const key = `${dep.file}:${dep.name}`;
@@ -378,6 +379,38 @@ function callImpact(db, file, startLine, endLine) {
378
379
  return [];
379
380
  }
380
381
  }
382
+ function cloneWarning(db, file, startLine, endLine) {
383
+ try {
384
+ const modified = db.prepare(
385
+ `SELECT node_id
386
+ FROM hex_line_symbol_annotations
387
+ WHERE file = ?
388
+ AND line_start <= ?
389
+ AND line_end >= ?`
390
+ ).all(file, endLine, startLine);
391
+ if (modified.length === 0) return [];
392
+ const clones = [];
393
+ const seen = /* @__PURE__ */ new Set();
394
+ for (const node of modified) {
395
+ const siblings = db.prepare(
396
+ `SELECT s2.file, s2.line_start, s2.display_name
397
+ FROM hex_line_clone_siblings s1
398
+ JOIN hex_line_clone_siblings s2 ON s2.norm_hash = s1.norm_hash AND s2.node_id != s1.node_id
399
+ WHERE s1.node_id = ?`
400
+ ).all(node.node_id);
401
+ for (const sib of siblings) {
402
+ const key = `${sib.file}:${sib.display_name}`;
403
+ if (!seen.has(key)) {
404
+ seen.add(key);
405
+ clones.push({ name: sib.display_name, file: sib.file, line: sib.line_start });
406
+ }
407
+ }
408
+ }
409
+ return clones.slice(0, 10);
410
+ } catch {
411
+ return [];
412
+ }
413
+ }
381
414
  function matchAnnotation(db, file, line) {
382
415
  try {
383
416
  const node = db.prepare(
@@ -1569,6 +1602,13 @@ ${serializeReadBlock(block)}`;
1569
1602
  \u26A0 Call impact: ${affected.length} callers in other files
1570
1603
  ${list}`;
1571
1604
  }
1605
+ const clones = cloneWarning(db, relFile, minLine, maxLine);
1606
+ if (clones.length > 0) {
1607
+ const list = clones.map((c) => `${c.file}:${c.line}`).join(", ");
1608
+ msg += `
1609
+
1610
+ \u26A0 ${clones.length} clone(s): ${list}`;
1611
+ }
1572
1612
  }
1573
1613
  } catch {
1574
1614
  }
@@ -1594,6 +1634,7 @@ try {
1594
1634
  var DEFAULT_LIMIT2 = 100;
1595
1635
  var MAX_OUTPUT = 10 * 1024 * 1024;
1596
1636
  var TIMEOUT2 = 3e4;
1637
+ var MAX_SEARCH_OUTPUT_CHARS = 8e4;
1597
1638
  function spawnRg(args) {
1598
1639
  return new Promise((resolve_, reject) => {
1599
1640
  let stdout = "";
@@ -1790,7 +1831,26 @@ async function contentMode(pattern, target, opts, plain, totalLimit) {
1790
1831
  }
1791
1832
  flushGroup();
1792
1833
  if (db) blocks.sort((a, b) => (b.meta.graphScore || 0) - (a.meta.graphScore || 0));
1793
- return blocks.map((block) => block.type === "edit_ready_block" ? serializeSearchBlock(block, { plain }) : serializeDiagnosticBlock(block)).join("\n\n");
1834
+ const parts = [];
1835
+ let budget = MAX_SEARCH_OUTPUT_CHARS;
1836
+ let capped = false;
1837
+ for (const block of blocks) {
1838
+ const serialized = block.type === "edit_ready_block" ? serializeSearchBlock(block, { plain }) : serializeDiagnosticBlock(block);
1839
+ if (parts.length > 0 && budget - serialized.length < 0) {
1840
+ capped = true;
1841
+ break;
1842
+ }
1843
+ parts.push(serialized);
1844
+ budget -= serialized.length;
1845
+ }
1846
+ if (capped) {
1847
+ const remaining = blocks.length - parts.length;
1848
+ parts.push(serializeDiagnosticBlock(buildDiagnosticBlock({
1849
+ kind: "output_capped",
1850
+ message: `OUTPUT_CAPPED: ${remaining} more search block(s) omitted (${MAX_SEARCH_OUTPUT_CHARS} char limit). Narrow with path= or glob= filters.`
1851
+ })));
1852
+ }
1853
+ return parts.join("\n\n");
1794
1854
  }
1795
1855
 
1796
1856
  // lib/outline.mjs
@@ -2786,7 +2846,7 @@ OUTPUT_CAPPED: Output exceeded ${MAX_BULK_OUTPUT_CHARS} chars.`;
2786
2846
  }
2787
2847
 
2788
2848
  // server.mjs
2789
- var version = true ? "1.8.0" : (await null).createRequire(import.meta.url)("./package.json").version;
2849
+ var version = true ? "1.9.0" : (await null).createRequire(import.meta.url)("./package.json").version;
2790
2850
  var { server, StdioServerTransport } = await createServerRuntime({
2791
2851
  name: "hex-line-mcp",
2792
2852
  version
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@levnikolaevich/hex-line-mcp",
3
- "version": "1.8.0",
3
+ "version": "1.9.0",
4
4
  "mcpName": "io.github.levnikolaevich/hex-line-mcp",
5
5
  "type": "module",
6
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.",