@levnikolaevich/hex-line-mcp 1.29.0 → 1.30.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/dist/server.mjs +163 -17
- package/package.json +1 -1
package/dist/server.mjs
CHANGED
|
@@ -202,11 +202,12 @@ function readText(filePath) {
|
|
|
202
202
|
// lib/security.mjs
|
|
203
203
|
var MAX_FILE_SIZE = 10 * 1024 * 1024;
|
|
204
204
|
var EXTERNAL_SAFE_FOLDERS = [
|
|
205
|
-
".hex-skills
|
|
206
|
-
".claude
|
|
205
|
+
".hex-skills",
|
|
206
|
+
".claude"
|
|
207
207
|
];
|
|
208
208
|
function isInExternalSafeFolder(absPath) {
|
|
209
|
-
|
|
209
|
+
const parts = normalizeScopeValue(absPath).split("/").filter(Boolean);
|
|
210
|
+
return EXTERNAL_SAFE_FOLDERS.some((folder) => parts.includes(folder));
|
|
210
211
|
}
|
|
211
212
|
function normalizePath(p) {
|
|
212
213
|
if (process.platform === "win32") {
|
|
@@ -5008,22 +5009,119 @@ OUTPUT_CAPPED: Output exceeded ${MAX_BULK_OUTPUT_CHARS} chars.`;
|
|
|
5008
5009
|
return output;
|
|
5009
5010
|
}
|
|
5010
5011
|
|
|
5012
|
+
// ../hex-common/src/runtime/error-classifier.mjs
|
|
5013
|
+
var FAILURE_CLASS = Object.freeze({
|
|
5014
|
+
NONE: "none",
|
|
5015
|
+
TIMEOUT_IDLE: "timeout_idle",
|
|
5016
|
+
TIMEOUT_PRODUCTIVE: "timeout_productive",
|
|
5017
|
+
PERMISSION_DENIAL: "permission_denial",
|
|
5018
|
+
TOOL_MISSING: "tool_missing",
|
|
5019
|
+
AUTH_MISSING: "auth_missing",
|
|
5020
|
+
RATE_LIMITED: "rate_limited",
|
|
5021
|
+
ASKED_QUESTION: "asked_question",
|
|
5022
|
+
AGENT_ERROR: "agent_error",
|
|
5023
|
+
UNKNOWN: "unknown"
|
|
5024
|
+
});
|
|
5025
|
+
var INPUT_ERROR_CODES = /* @__PURE__ */ new Set([
|
|
5026
|
+
"BAD_INPUT",
|
|
5027
|
+
"BAD_PATH",
|
|
5028
|
+
"BAD_REMOTE_PLATFORM",
|
|
5029
|
+
"INVALID_INPUT",
|
|
5030
|
+
"INVALID_EDIT_PAYLOAD",
|
|
5031
|
+
"INVALID_JSON",
|
|
5032
|
+
"PATH_OUTSIDE_ROOT",
|
|
5033
|
+
"PATH_NOT_FOUND",
|
|
5034
|
+
"FILE_NOT_FOUND",
|
|
5035
|
+
"FILE_OUTSIDE_PROJECT",
|
|
5036
|
+
"OUT_OF_RANGE",
|
|
5037
|
+
"UNSUPPORTED_REMOTE_PLATFORM"
|
|
5038
|
+
]);
|
|
5039
|
+
var PERMISSION_ERROR_CODES = /* @__PURE__ */ new Set([
|
|
5040
|
+
"SSH_HOST_NOT_ALLOWED",
|
|
5041
|
+
"BLOCKED_COMMAND",
|
|
5042
|
+
"REMOTE_SSH_DISABLED"
|
|
5043
|
+
]);
|
|
5044
|
+
var AUTH_ERROR_CODES = /* @__PURE__ */ new Set([
|
|
5045
|
+
"SSH_AUTH_FAILED",
|
|
5046
|
+
"SSH_AUTH_MISSING",
|
|
5047
|
+
"SSH_KEY_UNREADABLE"
|
|
5048
|
+
]);
|
|
5049
|
+
var TIMEOUT_ERROR_CODES = /* @__PURE__ */ new Set([
|
|
5050
|
+
"SSH_EXEC_TIMEOUT",
|
|
5051
|
+
"SSH_CONNECT_TIMEOUT",
|
|
5052
|
+
"EXEC_TIMEOUT",
|
|
5053
|
+
"TRANSFER_TIMEOUT"
|
|
5054
|
+
]);
|
|
5055
|
+
function textFor(input) {
|
|
5056
|
+
return [
|
|
5057
|
+
input?.code,
|
|
5058
|
+
input?.message,
|
|
5059
|
+
input?.recovery,
|
|
5060
|
+
input?.stderr,
|
|
5061
|
+
input?.error
|
|
5062
|
+
].filter(Boolean).map(String).join("\n");
|
|
5063
|
+
}
|
|
5064
|
+
function classifyMcpFailure(input = {}) {
|
|
5065
|
+
const code = String(input.code || "").toUpperCase();
|
|
5066
|
+
const text = textFor(input).toLowerCase();
|
|
5067
|
+
if (/\b(429|rate limit|too many requests|quota exceeded|throttl)/i.test(text) || code.includes("RATE_LIMIT")) {
|
|
5068
|
+
return { failure_class: FAILURE_CLASS.RATE_LIMITED, next_action: "defer_retry" };
|
|
5069
|
+
}
|
|
5070
|
+
if (/\b(auth|authentication|unauthorized|not authorized|login required|credential|token missing|no user for host|permission denied \(publickey\)|publickey)\b/i.test(text) || code.includes("AUTH") || AUTH_ERROR_CODES.has(code)) {
|
|
5071
|
+
return { failure_class: FAILURE_CLASS.AUTH_MISSING, next_action: "authenticate" };
|
|
5072
|
+
}
|
|
5073
|
+
if (/\b(eacces|eperm|permission denied|access denied|operation not permitted|forbidden)\b/i.test(text) || code === "GRAPH_DB_UNREADABLE" || PERMISSION_ERROR_CODES.has(code)) {
|
|
5074
|
+
return { failure_class: FAILURE_CLASS.PERMISSION_DENIAL, next_action: "fix_permissions" };
|
|
5075
|
+
}
|
|
5076
|
+
if (/\b(enoent|command not found|not recognized as|not found in path|required tool|provider setup failed|missing provider|tool missing)\b/i.test(text) || code === "GRAPH_PROVIDER_SETUP_FAILED") {
|
|
5077
|
+
return { failure_class: FAILURE_CLASS.TOOL_MISSING, next_action: "install_tool" };
|
|
5078
|
+
}
|
|
5079
|
+
if (/\b(etimedout|timed out|timeout|transfer_timeout|connection timed out|database is locked|busy or locked)\b/i.test(text) || code.includes("TIMEOUT") || code === "GRAPH_DB_BUSY" || TIMEOUT_ERROR_CODES.has(code)) {
|
|
5080
|
+
return { failure_class: FAILURE_CLASS.TIMEOUT_IDLE, next_action: "retry_after_wait" };
|
|
5081
|
+
}
|
|
5082
|
+
if (/\?\s*$|\b(please confirm|confirm\?|choose one|which option)\b/i.test(text)) {
|
|
5083
|
+
return { failure_class: FAILURE_CLASS.ASKED_QUESTION, next_action: "fix_inputs" };
|
|
5084
|
+
}
|
|
5085
|
+
if (INPUT_ERROR_CODES.has(code) || code.startsWith("INVALID_") || code.endsWith("_REQUIRED")) {
|
|
5086
|
+
return { failure_class: FAILURE_CLASS.UNKNOWN, next_action: "fix_inputs" };
|
|
5087
|
+
}
|
|
5088
|
+
return { failure_class: FAILURE_CLASS.UNKNOWN, next_action: "fix_inputs" };
|
|
5089
|
+
}
|
|
5090
|
+
|
|
5011
5091
|
// ../hex-common/src/runtime/results.mjs
|
|
5012
5092
|
var LARGE_RESULT_META = { "anthropic/maxResultSizeChars": 5e5 };
|
|
5013
|
-
function result(structured, { large = false } = {}) {
|
|
5093
|
+
function result(structured, { large = false, isError = null, errorStatuses = ["ERROR"] } = {}) {
|
|
5014
5094
|
const text = JSON.stringify(structured);
|
|
5015
5095
|
const response = {
|
|
5016
5096
|
content: [{ type: "text", text }],
|
|
5017
5097
|
structuredContent: structured
|
|
5018
5098
|
};
|
|
5019
5099
|
if (large) response._meta = LARGE_RESULT_META;
|
|
5020
|
-
|
|
5100
|
+
const resolvedError = isError === null ? new Set(errorStatuses).has(structured?.status) : isError;
|
|
5101
|
+
if (resolvedError) response.isError = true;
|
|
5021
5102
|
return response;
|
|
5022
5103
|
}
|
|
5023
5104
|
function errorResult(code, message, recovery, { large = false, extra = null } = {}) {
|
|
5105
|
+
const normalizedCode = String(code || "ERROR");
|
|
5106
|
+
const normalizedMessage = String(message || "Unknown MCP tool error");
|
|
5107
|
+
const normalizedRecovery = String(recovery || "Review the error and retry with corrected inputs");
|
|
5108
|
+
const classification = classifyMcpFailure({
|
|
5109
|
+
code: normalizedCode,
|
|
5110
|
+
message: normalizedMessage,
|
|
5111
|
+
recovery: normalizedRecovery
|
|
5112
|
+
});
|
|
5024
5113
|
const payload = {
|
|
5025
5114
|
status: "ERROR",
|
|
5026
|
-
|
|
5115
|
+
code: normalizedCode,
|
|
5116
|
+
summary: normalizedMessage,
|
|
5117
|
+
next_action: classification.next_action,
|
|
5118
|
+
recovery: normalizedRecovery,
|
|
5119
|
+
failure_class: classification.failure_class,
|
|
5120
|
+
error: {
|
|
5121
|
+
code: normalizedCode,
|
|
5122
|
+
message: normalizedMessage,
|
|
5123
|
+
recovery: normalizedRecovery
|
|
5124
|
+
}
|
|
5027
5125
|
};
|
|
5028
5126
|
if (extra && typeof extra === "object") {
|
|
5029
5127
|
Object.assign(payload, extra);
|
|
@@ -5032,9 +5130,17 @@ function errorResult(code, message, recovery, { large = false, extra = null } =
|
|
|
5032
5130
|
}
|
|
5033
5131
|
|
|
5034
5132
|
// server.mjs
|
|
5035
|
-
var version = true ? "1.
|
|
5133
|
+
var version = true ? "1.30.1" : (await null).createRequire(import.meta.url)("./package.json").version;
|
|
5036
5134
|
var STATUS_ENUM = z2.enum(STATUS_VALUES);
|
|
5037
5135
|
var ERROR_SHAPE = z2.object({ code: z2.string(), message: z2.string(), recovery: z2.string() }).optional();
|
|
5136
|
+
var ERROR_RESULT_FIELDS = {
|
|
5137
|
+
code: z2.string().optional(),
|
|
5138
|
+
summary: z2.string().optional(),
|
|
5139
|
+
next_action: z2.string().optional(),
|
|
5140
|
+
recovery: z2.string().optional(),
|
|
5141
|
+
failure_class: z2.string().optional(),
|
|
5142
|
+
error: ERROR_SHAPE
|
|
5143
|
+
};
|
|
5038
5144
|
var LINE_REPORT_KEYS = /* @__PURE__ */ new Set([
|
|
5039
5145
|
"status",
|
|
5040
5146
|
"reason",
|
|
@@ -5055,6 +5161,46 @@ var LINE_REPORT_KEYS = /* @__PURE__ */ new Set([
|
|
|
5055
5161
|
"remapped_refs",
|
|
5056
5162
|
"warnings"
|
|
5057
5163
|
]);
|
|
5164
|
+
var EDIT_PAYLOAD_TYPES = ["set_line", "insert_after", "replace_lines", "replace_between"];
|
|
5165
|
+
var EDIT_REQUIRED_FIELDS = {
|
|
5166
|
+
set_line: ["anchor", "new_text"],
|
|
5167
|
+
insert_after: ["anchor", "text"],
|
|
5168
|
+
replace_lines: ["start_anchor", "end_anchor", "new_text"],
|
|
5169
|
+
replace_between: ["start_anchor", "end_anchor", "new_text"]
|
|
5170
|
+
};
|
|
5171
|
+
function inputError(code, message, recovery) {
|
|
5172
|
+
const error = new Error(message);
|
|
5173
|
+
error.code = code;
|
|
5174
|
+
error.recovery = recovery;
|
|
5175
|
+
return error;
|
|
5176
|
+
}
|
|
5177
|
+
function validateEditPayload(edits) {
|
|
5178
|
+
if (!Array.isArray(edits) || edits.length === 0) {
|
|
5179
|
+
throw inputError("INVALID_EDIT_PAYLOAD", "BAD_INPUT: edits must be a non-empty JSON array", 'Pass canonical edit objects such as {"set_line":{"anchor":"ab.12","new_text":"..."}}');
|
|
5180
|
+
}
|
|
5181
|
+
edits.forEach((edit, index) => {
|
|
5182
|
+
if (!edit || typeof edit !== "object" || Array.isArray(edit)) {
|
|
5183
|
+
throw inputError("INVALID_EDIT_PAYLOAD", `BAD_INPUT: edit at index ${index} must be an object`, "Use one canonical edit object per array item");
|
|
5184
|
+
}
|
|
5185
|
+
const keys = EDIT_PAYLOAD_TYPES.filter((type2) => Object.prototype.hasOwnProperty.call(edit, type2));
|
|
5186
|
+
if (keys.length === 0) {
|
|
5187
|
+
throw inputError("INVALID_EDIT_PAYLOAD", `BAD_INPUT: unknown edit type at index ${index}`, "Use set_line, insert_after, replace_lines, or replace_between");
|
|
5188
|
+
}
|
|
5189
|
+
if (keys.length > 1) {
|
|
5190
|
+
throw inputError("INVALID_EDIT_PAYLOAD", `BAD_INPUT: edit at index ${index} has multiple edit types`, "Use exactly one edit type per object");
|
|
5191
|
+
}
|
|
5192
|
+
const [type] = keys;
|
|
5193
|
+
const payload = edit[type];
|
|
5194
|
+
if (!payload || typeof payload !== "object" || Array.isArray(payload)) {
|
|
5195
|
+
throw inputError("INVALID_EDIT_PAYLOAD", `BAD_INPUT: ${type} payload at index ${index} must be an object`, "Nest fields under the canonical edit type");
|
|
5196
|
+
}
|
|
5197
|
+
for (const field of EDIT_REQUIRED_FIELDS[type]) {
|
|
5198
|
+
if (typeof payload[field] !== "string") {
|
|
5199
|
+
throw inputError("INVALID_EDIT_PAYLOAD", `BAD_INPUT: ${type}.${field} must be a string at index ${index}`, "Provide all required canonical edit fields before retrying");
|
|
5200
|
+
}
|
|
5201
|
+
}
|
|
5202
|
+
});
|
|
5203
|
+
}
|
|
5058
5204
|
var { server, StdioServerTransport } = await createServerRuntime({
|
|
5059
5205
|
name: "hex-line-mcp",
|
|
5060
5206
|
version
|
|
@@ -5126,7 +5272,7 @@ server.registerTool("read_file", {
|
|
|
5126
5272
|
content: z2.string().optional(),
|
|
5127
5273
|
edit_ready: z2.boolean().optional(),
|
|
5128
5274
|
next_action: z2.string().optional(),
|
|
5129
|
-
|
|
5275
|
+
...ERROR_RESULT_FIELDS
|
|
5130
5276
|
}),
|
|
5131
5277
|
annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false }
|
|
5132
5278
|
}, async (rawParams) => {
|
|
@@ -5190,7 +5336,7 @@ server.registerTool("edit_file", {
|
|
|
5190
5336
|
conflict_policy: z2.enum(["strict", "conservative"]).optional().describe('Conflict handling (default: "conservative"). "conservative" returns structured CONFLICT output with recovery_ranges, retry_edit/retry_edits, suggested_read_call, and retry_plan when available.'),
|
|
5191
5337
|
allow_external: flexBool().describe("Allow editing a path outside the current project root. Use only when you intentionally target a temp or external file.")
|
|
5192
5338
|
}),
|
|
5193
|
-
outputSchema: z2.object({ status: STATUS_ENUM, file_path: z2.string().optional(), content: z2.string().optional(), reason: z2.string().optional(),
|
|
5339
|
+
outputSchema: z2.object({ status: STATUS_ENUM, file_path: z2.string().optional(), content: z2.string().optional(), reason: z2.string().optional(), warnings: z2.array(z2.object({ code: z2.string() }).passthrough()).optional(), ...ERROR_RESULT_FIELDS }),
|
|
5194
5340
|
annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: false }
|
|
5195
5341
|
}, async (rawParams) => {
|
|
5196
5342
|
const { file_path: p, edits: json, dry_run, restore_indent, base_revision, conflict_policy, allow_external } = rawParams ?? {};
|
|
@@ -5202,7 +5348,7 @@ server.registerTool("edit_file", {
|
|
|
5202
5348
|
} catch {
|
|
5203
5349
|
throw new Error('edits: invalid JSON. Expected: [{"set_line":{"anchor":"xx.N","new_text":"..."}}]');
|
|
5204
5350
|
}
|
|
5205
|
-
|
|
5351
|
+
validateEditPayload(parsed);
|
|
5206
5352
|
const content = editFile(p, parsed, {
|
|
5207
5353
|
dryRun: dry_run,
|
|
5208
5354
|
restoreIndent: restore_indent,
|
|
@@ -5222,7 +5368,7 @@ server.registerTool("write_file", {
|
|
|
5222
5368
|
content: z2.string().describe("File content"),
|
|
5223
5369
|
allow_external: flexBool().describe("Allow writing a path outside the current project root. Use only when you intentionally target a temp or external file.")
|
|
5224
5370
|
}),
|
|
5225
|
-
outputSchema: z2.object({ status: STATUS_ENUM, file_path: z2.string().optional(), lines: z2.number().optional(),
|
|
5371
|
+
outputSchema: z2.object({ status: STATUS_ENUM, file_path: z2.string().optional(), lines: z2.number().optional(), ...ERROR_RESULT_FIELDS }),
|
|
5226
5372
|
annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: true, openWorldHint: false }
|
|
5227
5373
|
}, async (rawParams) => {
|
|
5228
5374
|
const { file_path: p, content, allow_external } = rawParams ?? {};
|
|
@@ -5259,7 +5405,7 @@ server.registerTool("grep_search", {
|
|
|
5259
5405
|
edit_ready: flexBool().describe("Preserve hash/checksum search hunks in `content` mode. Default: false."),
|
|
5260
5406
|
allow_large_output: flexBool().describe("Bypass the default content-mode block/char caps when you intentionally need a larger payload.")
|
|
5261
5407
|
}),
|
|
5262
|
-
outputSchema: z2.object({ status: STATUS_ENUM, pattern: z2.string().optional(), content: z2.string().optional(),
|
|
5408
|
+
outputSchema: z2.object({ status: STATUS_ENUM, pattern: z2.string().optional(), content: z2.string().optional(), ...ERROR_RESULT_FIELDS }),
|
|
5263
5409
|
annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: true }
|
|
5264
5410
|
}, async (rawParams) => {
|
|
5265
5411
|
const {
|
|
@@ -5314,7 +5460,7 @@ server.registerTool("outline", {
|
|
|
5314
5460
|
inputSchema: z2.object({
|
|
5315
5461
|
file_path: z2.string().describe("Source file path")
|
|
5316
5462
|
}),
|
|
5317
|
-
outputSchema: z2.object({ status: STATUS_ENUM, file_path: z2.string().optional(), content: z2.string().optional(), reason: z2.string().optional(),
|
|
5463
|
+
outputSchema: z2.object({ status: STATUS_ENUM, file_path: z2.string().optional(), content: z2.string().optional(), reason: z2.string().optional(), ...ERROR_RESULT_FIELDS }),
|
|
5318
5464
|
annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false }
|
|
5319
5465
|
}, async (rawParams) => {
|
|
5320
5466
|
const { file_path: p } = rawParams ?? {};
|
|
@@ -5333,7 +5479,7 @@ server.registerTool("verify", {
|
|
|
5333
5479
|
checksums: z2.array(z2.string()).describe('Checksum strings, e.g. ["1-50:f7e2a1b0", "51-100:abcd1234"]'),
|
|
5334
5480
|
base_revision: z2.string().optional().describe("Optional prior revision to compare against latest state.")
|
|
5335
5481
|
}),
|
|
5336
|
-
outputSchema: z2.object({ status: STATUS_ENUM, file_path: z2.string().optional(), content: z2.string().optional(), reason: z2.string().optional(),
|
|
5482
|
+
outputSchema: z2.object({ status: STATUS_ENUM, file_path: z2.string().optional(), content: z2.string().optional(), reason: z2.string().optional(), ...ERROR_RESULT_FIELDS }),
|
|
5337
5483
|
annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false }
|
|
5338
5484
|
}, async (rawParams) => {
|
|
5339
5485
|
const { file_path: p, checksums, base_revision } = rawParams ?? {};
|
|
@@ -5360,7 +5506,7 @@ server.registerTool("inspect_path", {
|
|
|
5360
5506
|
format: z2.enum(["compact", "full"]).optional().describe('"compact" = shorter path view, "full" = include sizes/metadata where available'),
|
|
5361
5507
|
verbosity: z2.enum(["minimal", "compact", "full"]).optional().describe("Response budget. `minimal` returns the shortest tree summary.")
|
|
5362
5508
|
}),
|
|
5363
|
-
outputSchema: z2.object({ status: STATUS_ENUM, path: z2.string().optional(), content: z2.string().optional(), reason: z2.string().optional(),
|
|
5509
|
+
outputSchema: z2.object({ status: STATUS_ENUM, path: z2.string().optional(), content: z2.string().optional(), reason: z2.string().optional(), ...ERROR_RESULT_FIELDS }),
|
|
5364
5510
|
annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: true }
|
|
5365
5511
|
}, async (rawParams) => {
|
|
5366
5512
|
const { path: p, max_depth, max_entries, gitignore, format, pattern, type: entryType, verbosity } = rawParams ?? {};
|
|
@@ -5386,7 +5532,7 @@ server.registerTool("changes", {
|
|
|
5386
5532
|
path: z2.string().describe("File or directory path"),
|
|
5387
5533
|
compare_against: z2.string().optional().describe('Git ref to compare against (default: "HEAD")')
|
|
5388
5534
|
}),
|
|
5389
|
-
outputSchema: z2.object({ status: STATUS_ENUM, path: z2.string().optional(), content: z2.string().optional(),
|
|
5535
|
+
outputSchema: z2.object({ status: STATUS_ENUM, path: z2.string().optional(), content: z2.string().optional(), ...ERROR_RESULT_FIELDS }),
|
|
5390
5536
|
annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: true }
|
|
5391
5537
|
}, async (rawParams) => {
|
|
5392
5538
|
const { path: p, compare_against } = rawParams ?? {};
|
|
@@ -5409,7 +5555,7 @@ server.registerTool("bulk_replace", {
|
|
|
5409
5555
|
format: z2.enum(["compact", "full"]).optional().describe('"compact" (default) = summary only, "full" = include capped diffs'),
|
|
5410
5556
|
allow_external: flexBool().describe("Allow a replacement root outside the current project root. Use only when you intentionally target a temp or external directory.")
|
|
5411
5557
|
}),
|
|
5412
|
-
outputSchema: z2.object({ status: STATUS_ENUM, path: z2.string().optional(), content: z2.string().optional(), reason: z2.string().optional(),
|
|
5558
|
+
outputSchema: z2.object({ status: STATUS_ENUM, path: z2.string().optional(), content: z2.string().optional(), reason: z2.string().optional(), ...ERROR_RESULT_FIELDS }),
|
|
5413
5559
|
annotations: { readOnlyHint: false, destructiveHint: true, idempotentHint: false, openWorldHint: false }
|
|
5414
5560
|
}, async (rawParams) => {
|
|
5415
5561
|
try {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@levnikolaevich/hex-line-mcp",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.30.1",
|
|
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. 9 tools: inspect_path, read, edit, write, grep, outline, verify, changes, bulk_replace.",
|