@lousy-agents/mcp 5.14.7 → 5.14.9

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/mcp-server.js +143 -48
  2. package/package.json +1 -1
@@ -6559,7 +6559,7 @@ function escapeJsonPtr(str) {
6559
6559
 
6560
6560
 
6561
6561
  },
6562
- 2415(__unused_rspack_module, __unused_rspack___webpack_exports__, __webpack_require__) {
6562
+ 3523(__unused_rspack_module, __unused_rspack___webpack_exports__, __webpack_require__) {
6563
6563
  // NAMESPACE OBJECT: ../../node_modules/micromark/lib/constructs.js
6564
6564
  var constructs_namespaceObject = {};
6565
6565
  __webpack_require__.r(constructs_namespaceObject);
@@ -26791,7 +26791,7 @@ function splitSafeRelativePath(relativePath) {
26791
26791
  function resolveSafeRelativePath(rootDir, relativePath) {
26792
26792
  const root = path.resolve(rootDir);
26793
26793
  const target = path.resolve(root, ...splitSafeRelativePath(relativePath));
26794
- if (target !== root && !target.startsWith(root + path.sep)) {
26794
+ if (!path_isPathInside(root, target)) {
26795
26795
  throw new FsSafeError("outside-workspace", "relative path escapes root");
26796
26796
  }
26797
26797
  return target;
@@ -27126,6 +27126,85 @@ def reject_unsafe_endpoint(st):
27126
27126
  if stat.S_ISREG(mode) and st.st_nlink > 1:
27127
27127
  raise OSError(errno.EPERM, "hardlinked file endpoint is not allowed")
27128
27128
 
27129
+ def copy_bytes(source_fd, dest_fd):
27130
+ while True:
27131
+ chunk = os.read(source_fd, 65536)
27132
+ if not chunk:
27133
+ break
27134
+ view = memoryview(chunk)
27135
+ while view:
27136
+ written = os.write(dest_fd, view)
27137
+ if written <= 0:
27138
+ raise OSError(errno.EIO, "short write")
27139
+ view = view[written:]
27140
+
27141
+ def write_all(fd, data):
27142
+ view = memoryview(data)
27143
+ while view:
27144
+ written = os.write(fd, view)
27145
+ if written <= 0:
27146
+ raise OSError(errno.EIO, "short write")
27147
+ view = view[written:]
27148
+
27149
+ def link_unsupported(exc):
27150
+ unsupported = (errno.EPERM, errno.EOPNOTSUPP, getattr(errno, "ENOTSUP", errno.EOPNOTSUPP))
27151
+ return getattr(exc, "errno", None) in unsupported
27152
+
27153
+ def link_no_replace(name, new_name, source_fd, target_fd):
27154
+ linked = False
27155
+ try:
27156
+ os.link(name, new_name, src_dir_fd=source_fd, dst_dir_fd=target_fd, follow_symlinks=False)
27157
+ linked = True
27158
+ os.unlink(name, dir_fd=source_fd)
27159
+ except Exception:
27160
+ if linked:
27161
+ try: os.unlink(new_name, dir_fd=target_fd)
27162
+ except FileNotFoundError: pass
27163
+ raise
27164
+ os.fsync(source_fd)
27165
+ if source_fd != target_fd:
27166
+ os.fsync(target_fd)
27167
+
27168
+ def copy_file_no_replace(source_parent_fd, source_name, target_parent_fd, basename, mode, expected=None, unlink_source=False):
27169
+ source_fd = os.open(source_name, READ_FLAGS, dir_fd=source_parent_fd)
27170
+ dest_fd = None
27171
+ success = False
27172
+ try:
27173
+ if expected is not None:
27174
+ source_stat = os.fstat(source_fd)
27175
+ if source_stat.st_dev != expected.st_dev or source_stat.st_ino != expected.st_ino:
27176
+ raise RuntimeError("fs-safe-source-mismatch")
27177
+ dest_fd = os.open(basename, WRITE_FLAGS, mode, dir_fd=target_parent_fd)
27178
+ copy_bytes(source_fd, dest_fd)
27179
+ os.fsync(dest_fd)
27180
+ success = True
27181
+ finally:
27182
+ os.close(source_fd)
27183
+ if dest_fd is not None:
27184
+ os.close(dest_fd)
27185
+ if dest_fd is not None and not success:
27186
+ try: os.unlink(basename, dir_fd=target_parent_fd)
27187
+ except FileNotFoundError: pass
27188
+ if unlink_source:
27189
+ try:
27190
+ os.unlink(source_name, dir_fd=source_parent_fd)
27191
+ except Exception:
27192
+ try: os.unlink(basename, dir_fd=target_parent_fd)
27193
+ except FileNotFoundError: pass
27194
+ raise
27195
+
27196
+ def commit_temp_file(parent_fd, temp_name, basename, overwrite, mode):
27197
+ if overwrite:
27198
+ os.replace(temp_name, basename, src_dir_fd=parent_fd, dst_dir_fd=parent_fd)
27199
+ else:
27200
+ try:
27201
+ os.link(temp_name, basename, src_dir_fd=parent_fd, dst_dir_fd=parent_fd, follow_symlinks=False)
27202
+ os.unlink(temp_name, dir_fd=parent_fd)
27203
+ except OSError as exc:
27204
+ if not link_unsupported(exc):
27205
+ raise
27206
+ copy_file_no_replace(parent_fd, temp_name, parent_fd, basename, mode, unlink_source=True)
27207
+
27129
27208
  def stat_path(root_fd, payload):
27130
27209
  relative = payload.get("relativePath", "")
27131
27210
  segments = split_relative(relative)
@@ -27200,7 +27279,18 @@ def rename_path(root_fd, payload):
27200
27279
  try:
27201
27280
  from_stat = os.lstat(from_base, dir_fd=from_parent_fd)
27202
27281
  reject_unsafe_endpoint(from_stat)
27203
- if not payload.get("overwrite", True):
27282
+ overwrite = payload.get("overwrite", True)
27283
+ if not overwrite and stat.S_ISREG(from_stat.st_mode):
27284
+ try:
27285
+ link_no_replace(from_base, to_base, from_parent_fd, to_parent_fd)
27286
+ except OSError as exc:
27287
+ if not link_unsupported(exc):
27288
+ raise
27289
+ copy_file_no_replace(from_parent_fd, from_base, to_parent_fd, to_base, stat.S_IMODE(from_stat.st_mode), from_stat, True)
27290
+ return None
27291
+ if not overwrite and stat.S_ISDIR(from_stat.st_mode):
27292
+ raise RuntimeError("fs-safe-directory-noreplace-unsupported")
27293
+ if not overwrite:
27204
27294
  try:
27205
27295
  os.lstat(to_base, dir_fd=to_parent_fd)
27206
27296
  raise FileExistsError(errno.EEXIST, "destination exists", to_base)
@@ -27245,16 +27335,11 @@ def write_path(root_fd, payload):
27245
27335
  except FileNotFoundError:
27246
27336
  pass
27247
27337
  temp_name, temp_fd = create_temp_file(parent_fd, basename, mode)
27248
- view = memoryview(data)
27249
- while view:
27250
- written = os.write(temp_fd, view)
27251
- if written <= 0:
27252
- raise OSError(errno.EIO, "short write")
27253
- view = view[written:]
27338
+ write_all(temp_fd, data)
27254
27339
  os.fsync(temp_fd)
27255
27340
  os.close(temp_fd)
27256
27341
  temp_fd = None
27257
- os.replace(temp_name, basename, src_dir_fd=parent_fd, dst_dir_fd=parent_fd)
27342
+ commit_temp_file(parent_fd, temp_name, basename, overwrite, mode)
27258
27343
  temp_name = None
27259
27344
  os.fsync(parent_fd)
27260
27345
  result_stat = os.stat(basename, dir_fd=parent_fd, follow_symlinks=False)
@@ -27287,12 +27372,6 @@ def copy_path(root_fd, payload):
27287
27372
  if max_bytes >= 0 and source_stat.st_size > max_bytes:
27288
27373
  raise RuntimeError("fs-safe-too-large:%d:%d" % (max_bytes, source_stat.st_size))
27289
27374
  parent_fd = walk_dir(root_fd, split_relative(payload.get("relativeParentPath", "")), bool(payload.get("mkdir", True)))
27290
- if not overwrite:
27291
- try:
27292
- os.lstat(basename, dir_fd=parent_fd)
27293
- raise FileExistsError(errno.EEXIST, "destination exists", basename)
27294
- except FileNotFoundError:
27295
- pass
27296
27375
  temp_name, temp_fd = create_temp_file(parent_fd, basename, mode)
27297
27376
  written_bytes = 0
27298
27377
  while True:
@@ -27311,7 +27390,7 @@ def copy_path(root_fd, payload):
27311
27390
  os.fsync(temp_fd)
27312
27391
  os.close(temp_fd)
27313
27392
  temp_fd = None
27314
- os.replace(temp_name, basename, src_dir_fd=parent_fd, dst_dir_fd=parent_fd)
27393
+ commit_temp_file(parent_fd, temp_name, basename, overwrite, mode)
27315
27394
  temp_name = None
27316
27395
  os.fsync(parent_fd)
27317
27396
  result_stat = os.stat(basename, dir_fd=parent_fd, follow_symlinks=False)
@@ -27435,6 +27514,9 @@ function mapWorkerError(response) {
27435
27514
  if (message.includes("fs-safe-source-mismatch")) {
27436
27515
  return new errors_FsSafeError("path-mismatch", "source path changed during copy");
27437
27516
  }
27517
+ if (message.includes("fs-safe-directory-noreplace-unsupported")) {
27518
+ return new errors_FsSafeError("invalid-path", "directory moves require overwrite: true");
27519
+ }
27438
27520
  if (code === "FileNotFoundError" || errno === 2) {
27439
27521
  return new errors_FsSafeError("not-found", "file not found");
27440
27522
  }
@@ -27452,19 +27534,19 @@ function mapWorkerError(response) {
27452
27534
  }
27453
27535
  return new errors_FsSafeError("helper-failed", message);
27454
27536
  }
27455
- function rejectPending(error) {
27456
- if (!worker) {
27537
+ function rejectPending(error, targetWorker = worker) {
27538
+ if (!targetWorker || worker !== targetWorker) {
27457
27539
  return;
27458
27540
  }
27459
- setWorkerRef(worker, false);
27460
- for (const pending of worker.pending.values()) {
27541
+ setWorkerRef(targetWorker, false);
27542
+ for (const pending of targetWorker.pending.values()) {
27461
27543
  pending.reject(error);
27462
27544
  }
27463
- worker.pending.clear();
27545
+ targetWorker.pending.clear();
27464
27546
  worker = null;
27465
27547
  }
27466
- function handleWorkerLine(line) {
27467
- if (!worker || !line.trim()) {
27548
+ function handleWorkerLine(currentWorker, line) {
27549
+ if (worker !== currentWorker || !line.trim()) {
27468
27550
  return;
27469
27551
  }
27470
27552
  let decoded;
@@ -27472,11 +27554,11 @@ function handleWorkerLine(line) {
27472
27554
  decoded = JSON.parse(line);
27473
27555
  }
27474
27556
  catch {
27475
- rejectPending(new errors_FsSafeError("helper-failed", `pinned helper returned invalid JSON: ${line}`));
27557
+ rejectPending(new errors_FsSafeError("helper-failed", `pinned helper returned invalid JSON: ${line}`), currentWorker);
27476
27558
  return;
27477
27559
  }
27478
27560
  if (typeof decoded !== "object" || decoded === null || !("id" in decoded)) {
27479
- rejectPending(new errors_FsSafeError("helper-failed", "pinned helper returned invalid response"));
27561
+ rejectPending(new errors_FsSafeError("helper-failed", "pinned helper returned invalid response"), currentWorker);
27480
27562
  return;
27481
27563
  }
27482
27564
  const response = decoded;
@@ -27484,13 +27566,13 @@ function handleWorkerLine(line) {
27484
27566
  if (id === undefined) {
27485
27567
  return;
27486
27568
  }
27487
- const pending = worker.pending.get(id);
27569
+ const pending = currentWorker.pending.get(id);
27488
27570
  if (!pending) {
27489
27571
  return;
27490
27572
  }
27491
- worker.pending.delete(id);
27492
- if (worker.pending.size === 0) {
27493
- setWorkerRef(worker, false);
27573
+ currentWorker.pending.delete(id);
27574
+ if (currentWorker.pending.size === 0) {
27575
+ setWorkerRef(currentWorker, false);
27494
27576
  }
27495
27577
  if (response.ok === true) {
27496
27578
  pending.resolve(response.result);
@@ -27506,28 +27588,28 @@ function getWorker() {
27506
27588
  const child = (0,external_node_child_process_.spawn)(resolvePython(), ["-u", "-c", PINNED_PYTHON_WORKER_SOURCE], {
27507
27589
  stdio: ["pipe", "pipe", "pipe"],
27508
27590
  });
27509
- worker = { child, pending: new Map(), stderr: "", stdoutBuffer: "" };
27591
+ const currentWorker = { child, pending: new Map(), stderr: "", stdoutBuffer: "" };
27592
+ worker = currentWorker;
27510
27593
  child.stdout.setEncoding("utf8");
27511
27594
  child.stderr.setEncoding("utf8");
27512
27595
  child.stdout.on("data", (chunk) => {
27513
- const current = worker;
27514
- if (!current) {
27596
+ if (worker !== currentWorker) {
27515
27597
  return;
27516
27598
  }
27517
- current.stdoutBuffer += chunk;
27599
+ currentWorker.stdoutBuffer += chunk;
27518
27600
  for (;;) {
27519
- const newline = current.stdoutBuffer.indexOf("\n");
27601
+ const newline = currentWorker.stdoutBuffer.indexOf("\n");
27520
27602
  if (newline < 0) {
27521
27603
  break;
27522
27604
  }
27523
- const line = current.stdoutBuffer.slice(0, newline);
27524
- current.stdoutBuffer = current.stdoutBuffer.slice(newline + 1);
27525
- handleWorkerLine(line);
27605
+ const line = currentWorker.stdoutBuffer.slice(0, newline);
27606
+ currentWorker.stdoutBuffer = currentWorker.stdoutBuffer.slice(newline + 1);
27607
+ handleWorkerLine(currentWorker, line);
27526
27608
  }
27527
27609
  });
27528
27610
  child.stderr.on("data", (chunk) => {
27529
- if (worker) {
27530
- worker.stderr = `${worker.stderr}${chunk}`.slice(-4096);
27611
+ if (worker === currentWorker) {
27612
+ currentWorker.stderr = `${currentWorker.stderr}${chunk}`.slice(-4096);
27531
27613
  }
27532
27614
  });
27533
27615
  child.once("error", (error) => {
@@ -27536,17 +27618,17 @@ function getWorker() {
27536
27618
  : error instanceof Error
27537
27619
  ? error
27538
27620
  : new Error(String(error));
27539
- rejectPending(mapped);
27621
+ rejectPending(mapped, currentWorker);
27540
27622
  });
27541
27623
  child.once("close", (code, signal) => {
27542
- const stderr = worker?.stderr.trim();
27543
- rejectPending(new errors_FsSafeError("helper-failed", stderr || `pinned helper exited with code ${code ?? "null"} (${signal ?? "?"})`));
27624
+ const stderr = currentWorker.stderr.trim();
27625
+ rejectPending(new errors_FsSafeError("helper-failed", stderr || `pinned helper exited with code ${code ?? "null"} (${signal ?? "?"})`), currentWorker);
27544
27626
  });
27545
27627
  process.once("exit", () => {
27546
27628
  child.kill("SIGTERM");
27547
27629
  });
27548
- setWorkerRef(worker, false);
27549
- return worker;
27630
+ setWorkerRef(currentWorker, false);
27631
+ return currentWorker;
27550
27632
  }
27551
27633
  function setRefable(value, ref) {
27552
27634
  if (!value) {
@@ -28793,6 +28875,15 @@ function __setFsSafeTestHooksForTest(hooks) {
28793
28875
  test_hooks_fsSafeTestHooks = hooks;
28794
28876
  }
28795
28877
 
28878
+ ;// CONCATENATED MODULE: ../../node_modules/@openclaw/fs-safe/dist/json-stringify.js
28879
+ function stringifyJsonDocument(value, replacer, space) {
28880
+ const text = JSON.stringify(value, replacer, space);
28881
+ if (typeof text !== "string") {
28882
+ throw new TypeError("value is not representable as a JSON document");
28883
+ }
28884
+ return text;
28885
+ }
28886
+
28796
28887
  ;// CONCATENATED MODULE: ../../node_modules/@openclaw/fs-safe/dist/temp-cleanup.js
28797
28888
 
28798
28889
  const tempCleanupEntries = new Map();
@@ -28880,6 +28971,7 @@ async function serializePathWrite(key, run) {
28880
28971
 
28881
28972
 
28882
28973
 
28974
+
28883
28975
 
28884
28976
 
28885
28977
  function logWarn(message) {
@@ -29120,12 +29212,12 @@ class RootHandle {
29120
29212
  }
29121
29213
  async writeJson(relativePath, data, options = {}) {
29122
29214
  const { replacer, space, trailingNewline = true, ...writeOptions } = options;
29123
- const json = JSON.stringify(data, replacer, space);
29215
+ const json = stringifyJsonDocument(data, replacer, space);
29124
29216
  await this.write(relativePath, trailingNewline ? `${json}\n` : json, writeOptions);
29125
29217
  }
29126
29218
  async createJson(relativePath, data, options = {}) {
29127
29219
  const { replacer, space, trailingNewline = true, ...writeOptions } = options;
29128
- const json = JSON.stringify(data, replacer, space);
29220
+ const json = stringifyJsonDocument(data, replacer, space);
29129
29221
  await this.create(relativePath, trailingNewline ? `${json}\n` : json, writeOptions);
29130
29222
  }
29131
29223
  async copyIn(relativePath, sourcePath, options = {}) {
@@ -29910,6 +30002,9 @@ async function movePathFallback(root, params) {
29910
30002
  if (sourceStat.isFile() && sourceStat.nlink > 1) {
29911
30003
  throw new errors_FsSafeError("hardlink", "hardlinked path not allowed");
29912
30004
  }
30005
+ if (!params.overwrite && sourceStat.isDirectory()) {
30006
+ throw new errors_FsSafeError("invalid-path", "directory moves require overwrite: true");
30007
+ }
29913
30008
  if (!params.overwrite) {
29914
30009
  try {
29915
30010
  await promises_.lstat(target.resolved);
@@ -68063,4 +68158,4 @@ if (installedChunkData !== 0) { // 0 means "already installed".'
68063
68158
  // module factories are used so entry inlining is disabled
68064
68159
  // startup
68065
68160
  // Load entry module and return exports
68066
- var __webpack_exports__ = __webpack_require__(2415);
68161
+ var __webpack_exports__ = __webpack_require__(3523);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lousy-agents/mcp",
3
- "version": "5.14.7",
3
+ "version": "5.14.9",
4
4
  "description": "MCP server for lousy-agents - provides AI coding assistant tools via the Model Context Protocol",
5
5
  "type": "module",
6
6
  "repository": {