@lousy-agents/mcp 5.14.8 → 5.14.10
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/mcp-server.js +237 -123
- package/package.json +1 -1
package/dist/mcp-server.js
CHANGED
|
@@ -6559,7 +6559,7 @@ function escapeJsonPtr(str) {
|
|
|
6559
6559
|
|
|
6560
6560
|
|
|
6561
6561
|
},
|
|
6562
|
-
|
|
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);
|
|
@@ -26726,6 +26726,9 @@ function path_isPathInside(root, target) {
|
|
|
26726
26726
|
const firstSegment = relative.split(external_node_path_.posix.sep)[0];
|
|
26727
26727
|
return relative === "" || (firstSegment !== ".." && !external_node_path_.isAbsolute(relative));
|
|
26728
26728
|
}
|
|
26729
|
+
function isPathRelativeEscape(relativePath) {
|
|
26730
|
+
return relativePath === ".." || relativePath.startsWith(`..${external_node_path_.sep}`) || external_node_path_.isAbsolute(relativePath);
|
|
26731
|
+
}
|
|
26729
26732
|
function resolveSafeBaseDir(rootDir) {
|
|
26730
26733
|
const resolved = path.resolve(rootDir);
|
|
26731
26734
|
return resolved.endsWith(path.sep) ? resolved : `${resolved}${path.sep}`;
|
|
@@ -26791,7 +26794,7 @@ function splitSafeRelativePath(relativePath) {
|
|
|
26791
26794
|
function resolveSafeRelativePath(rootDir, relativePath) {
|
|
26792
26795
|
const root = path.resolve(rootDir);
|
|
26793
26796
|
const target = path.resolve(root, ...splitSafeRelativePath(relativePath));
|
|
26794
|
-
if (
|
|
26797
|
+
if (!path_isPathInside(root, target)) {
|
|
26795
26798
|
throw new FsSafeError("outside-workspace", "relative path escapes root");
|
|
26796
26799
|
}
|
|
26797
26800
|
return target;
|
|
@@ -26874,17 +26877,17 @@ function directory_guard_createNearestExistingSyncDirectoryGuard(rootReal, targe
|
|
|
26874
26877
|
|
|
26875
26878
|
|
|
26876
26879
|
|
|
26880
|
+
|
|
26877
26881
|
function isSameOrChildPath(candidate, parent) {
|
|
26878
|
-
|
|
26879
|
-
|
|
26880
|
-
function isPathEscape(relativePath) {
|
|
26881
|
-
return relativePath === ".." || relativePath.startsWith(`..${external_node_path_.sep}`) || external_node_path_.isAbsolute(relativePath);
|
|
26882
|
+
const parentPrefix = parent.endsWith(external_node_path_.sep) ? parent : `${parent}${external_node_path_.sep}`;
|
|
26883
|
+
return candidate === parent || candidate.startsWith(parentPrefix);
|
|
26882
26884
|
}
|
|
26883
26885
|
async function mkdirPathComponentsWithGuards(params) {
|
|
26884
26886
|
const root = external_node_path_.resolve(params.rootReal);
|
|
26887
|
+
const rootCanonical = external_node_path_.resolve(await promises_.realpath(root));
|
|
26885
26888
|
const target = external_node_path_.resolve(params.targetPath);
|
|
26886
26889
|
const relative = external_node_path_.relative(root, target);
|
|
26887
|
-
if (
|
|
26890
|
+
if (isPathRelativeEscape(relative)) {
|
|
26888
26891
|
throw new errors_FsSafeError("outside-workspace", "directory is outside workspace root");
|
|
26889
26892
|
}
|
|
26890
26893
|
let current = root;
|
|
@@ -26907,7 +26910,7 @@ async function mkdirPathComponentsWithGuards(params) {
|
|
|
26907
26910
|
}
|
|
26908
26911
|
// Node's recursive mkdir follows symlinks in missing components. Build one
|
|
26909
26912
|
// segment at a time and realpath-check each segment before descending.
|
|
26910
|
-
if (!isSameOrChildPath(external_node_path_.resolve(await promises_.realpath(next)),
|
|
26913
|
+
if (!isSameOrChildPath(external_node_path_.resolve(await promises_.realpath(next)), rootCanonical)) {
|
|
26911
26914
|
throw new errors_FsSafeError("outside-workspace", "directory escaped workspace root");
|
|
26912
26915
|
}
|
|
26913
26916
|
await directory_guard_createAsyncDirectoryGuard(next);
|
|
@@ -27042,26 +27045,20 @@ var external_node_child_process_ = __webpack_require__(1421);
|
|
|
27042
27045
|
|
|
27043
27046
|
|
|
27044
27047
|
const PINNED_PYTHON_WORKER_SOURCE = String.raw `
|
|
27045
|
-
import base64
|
|
27046
|
-
import errno
|
|
27047
|
-
import json
|
|
27048
|
-
import os
|
|
27049
|
-
import secrets
|
|
27050
|
-
import stat
|
|
27051
|
-
import sys
|
|
27052
|
-
|
|
27048
|
+
import base64, errno, json, os, secrets, stat, sys
|
|
27053
27049
|
DIR_FLAGS = os.O_RDONLY
|
|
27054
27050
|
if hasattr(os, "O_DIRECTORY"):
|
|
27055
27051
|
DIR_FLAGS |= os.O_DIRECTORY
|
|
27056
27052
|
if hasattr(os, "O_NOFOLLOW"):
|
|
27057
27053
|
DIR_FLAGS |= os.O_NOFOLLOW
|
|
27058
27054
|
READ_FLAGS = os.O_RDONLY
|
|
27055
|
+
if hasattr(os, "O_NONBLOCK"):
|
|
27056
|
+
READ_FLAGS |= os.O_NONBLOCK
|
|
27059
27057
|
if hasattr(os, "O_NOFOLLOW"):
|
|
27060
27058
|
READ_FLAGS |= os.O_NOFOLLOW
|
|
27061
27059
|
WRITE_FLAGS = os.O_WRONLY | os.O_CREAT | os.O_EXCL
|
|
27062
27060
|
if hasattr(os, "O_NOFOLLOW"):
|
|
27063
27061
|
WRITE_FLAGS |= os.O_NOFOLLOW
|
|
27064
|
-
|
|
27065
27062
|
def split_relative(value):
|
|
27066
27063
|
if value in ("", "."):
|
|
27067
27064
|
return []
|
|
@@ -27074,10 +27071,8 @@ def split_relative(value):
|
|
|
27074
27071
|
if part == "..":
|
|
27075
27072
|
raise OSError(errno.EPERM, "path traversal is not allowed")
|
|
27076
27073
|
return parts
|
|
27077
|
-
|
|
27078
27074
|
def open_dir(path_value, dir_fd=None):
|
|
27079
27075
|
return os.open(path_value, DIR_FLAGS, dir_fd=dir_fd)
|
|
27080
|
-
|
|
27081
27076
|
def walk_dir(root_fd, segments, mkdir_enabled=False):
|
|
27082
27077
|
current_fd = os.dup(root_fd)
|
|
27083
27078
|
try:
|
|
@@ -27095,14 +27090,12 @@ def walk_dir(root_fd, segments, mkdir_enabled=False):
|
|
|
27095
27090
|
except Exception:
|
|
27096
27091
|
os.close(current_fd)
|
|
27097
27092
|
raise
|
|
27098
|
-
|
|
27099
27093
|
def parent_and_basename(root_fd, relative):
|
|
27100
27094
|
segments = split_relative(relative)
|
|
27101
27095
|
if not segments:
|
|
27102
27096
|
raise OSError(errno.EPERM, "operation requires a non-root path")
|
|
27103
27097
|
parent_fd = walk_dir(root_fd, segments[:-1])
|
|
27104
27098
|
return parent_fd, segments[-1]
|
|
27105
|
-
|
|
27106
27099
|
def encode_stat(st):
|
|
27107
27100
|
mode = st.st_mode
|
|
27108
27101
|
return {
|
|
@@ -27118,14 +27111,108 @@ def encode_stat(st):
|
|
|
27118
27111
|
"size": st.st_size,
|
|
27119
27112
|
"uid": st.st_uid,
|
|
27120
27113
|
}
|
|
27121
|
-
|
|
27122
27114
|
def reject_unsafe_endpoint(st):
|
|
27123
27115
|
mode = st.st_mode
|
|
27124
27116
|
if stat.S_ISLNK(mode):
|
|
27125
27117
|
raise OSError(errno.ELOOP, "symlink endpoint is not allowed")
|
|
27126
27118
|
if stat.S_ISREG(mode) and st.st_nlink > 1:
|
|
27127
27119
|
raise OSError(errno.EPERM, "hardlinked file endpoint is not allowed")
|
|
27128
|
-
|
|
27120
|
+
def copy_bytes(source_fd, dest_fd):
|
|
27121
|
+
while True:
|
|
27122
|
+
chunk = os.read(source_fd, 65536)
|
|
27123
|
+
if not chunk:
|
|
27124
|
+
break
|
|
27125
|
+
view = memoryview(chunk)
|
|
27126
|
+
while view:
|
|
27127
|
+
written = os.write(dest_fd, view)
|
|
27128
|
+
if written <= 0:
|
|
27129
|
+
raise OSError(errno.EIO, "short write")
|
|
27130
|
+
view = view[written:]
|
|
27131
|
+
def write_all(fd, data):
|
|
27132
|
+
view = memoryview(data)
|
|
27133
|
+
while view:
|
|
27134
|
+
written = os.write(fd, view)
|
|
27135
|
+
if written <= 0:
|
|
27136
|
+
raise OSError(errno.EIO, "short write")
|
|
27137
|
+
view = view[written:]
|
|
27138
|
+
def link_unsupported(exc):
|
|
27139
|
+
unsupported = (errno.EPERM, errno.EOPNOTSUPP, getattr(errno, "ENOTSUP", errno.EOPNOTSUPP))
|
|
27140
|
+
return getattr(exc, "errno", None) in unsupported
|
|
27141
|
+
def link_no_replace(name, new_name, source_fd, target_fd):
|
|
27142
|
+
linked = False
|
|
27143
|
+
try:
|
|
27144
|
+
os.link(name, new_name, src_dir_fd=source_fd, dst_dir_fd=target_fd, follow_symlinks=False)
|
|
27145
|
+
linked = True
|
|
27146
|
+
os.unlink(name, dir_fd=source_fd)
|
|
27147
|
+
except Exception:
|
|
27148
|
+
if linked:
|
|
27149
|
+
try: os.unlink(new_name, dir_fd=target_fd)
|
|
27150
|
+
except FileNotFoundError: pass
|
|
27151
|
+
raise
|
|
27152
|
+
os.fsync(source_fd)
|
|
27153
|
+
if source_fd != target_fd:
|
|
27154
|
+
os.fsync(target_fd)
|
|
27155
|
+
def copy_file_no_replace(source_parent_fd, source_name, target_parent_fd, basename, mode, expected=None, unlink_source=False):
|
|
27156
|
+
source_fd = os.open(source_name, READ_FLAGS, dir_fd=source_parent_fd)
|
|
27157
|
+
dest_fd = None; success = False; dest_stat = None
|
|
27158
|
+
try:
|
|
27159
|
+
if expected is not None:
|
|
27160
|
+
source_stat = os.fstat(source_fd)
|
|
27161
|
+
if source_stat.st_dev != expected.st_dev or source_stat.st_ino != expected.st_ino:
|
|
27162
|
+
raise RuntimeError("fs-safe-source-mismatch")
|
|
27163
|
+
dest_fd = os.open(basename, WRITE_FLAGS, mode, dir_fd=target_parent_fd)
|
|
27164
|
+
copy_bytes(source_fd, dest_fd)
|
|
27165
|
+
os.fsync(dest_fd)
|
|
27166
|
+
dest_stat = os.fstat(dest_fd)
|
|
27167
|
+
success = True
|
|
27168
|
+
finally:
|
|
27169
|
+
os.close(source_fd)
|
|
27170
|
+
if dest_fd is not None:
|
|
27171
|
+
os.close(dest_fd)
|
|
27172
|
+
if dest_fd is not None and not success:
|
|
27173
|
+
try: os.unlink(basename, dir_fd=target_parent_fd)
|
|
27174
|
+
except FileNotFoundError: pass
|
|
27175
|
+
if unlink_source:
|
|
27176
|
+
try:
|
|
27177
|
+
os.unlink(source_name, dir_fd=source_parent_fd)
|
|
27178
|
+
except Exception:
|
|
27179
|
+
try: os.unlink(basename, dir_fd=target_parent_fd)
|
|
27180
|
+
except FileNotFoundError: pass
|
|
27181
|
+
raise
|
|
27182
|
+
return dest_stat
|
|
27183
|
+
def same_identity(left, right):
|
|
27184
|
+
return left.st_dev == right.st_dev and left.st_ino == right.st_ino
|
|
27185
|
+
def verify_temp_name(parent_fd, temp_name, expected_stat):
|
|
27186
|
+
current_stat = os.lstat(temp_name, dir_fd=parent_fd)
|
|
27187
|
+
if stat.S_ISLNK(current_stat.st_mode) or not same_identity(current_stat, expected_stat):
|
|
27188
|
+
raise RuntimeError("fs-safe-temp-mismatch")
|
|
27189
|
+
def verify_committed_temp(parent_fd, basename, expected_stat):
|
|
27190
|
+
final_stat = os.lstat(basename, dir_fd=parent_fd)
|
|
27191
|
+
if not stat.S_ISLNK(final_stat.st_mode) and same_identity(final_stat, expected_stat):
|
|
27192
|
+
return final_stat
|
|
27193
|
+
try: os.unlink(basename, dir_fd=parent_fd)
|
|
27194
|
+
except FileNotFoundError: pass
|
|
27195
|
+
raise RuntimeError("fs-safe-temp-mismatch")
|
|
27196
|
+
def commit_temp_file(parent_fd, temp_name, basename, overwrite, mode, expected_stat):
|
|
27197
|
+
verify_temp_name(parent_fd, temp_name, expected_stat)
|
|
27198
|
+
if overwrite:
|
|
27199
|
+
os.replace(temp_name, basename, src_dir_fd=parent_fd, dst_dir_fd=parent_fd)
|
|
27200
|
+
return verify_committed_temp(parent_fd, basename, expected_stat)
|
|
27201
|
+
else:
|
|
27202
|
+
try:
|
|
27203
|
+
os.link(temp_name, basename, src_dir_fd=parent_fd, dst_dir_fd=parent_fd, follow_symlinks=False)
|
|
27204
|
+
final_stat = verify_committed_temp(parent_fd, basename, expected_stat)
|
|
27205
|
+
os.unlink(temp_name, dir_fd=parent_fd)
|
|
27206
|
+
return final_stat
|
|
27207
|
+
except OSError as exc:
|
|
27208
|
+
if not link_unsupported(exc):
|
|
27209
|
+
raise
|
|
27210
|
+
return copy_file_no_replace(parent_fd, temp_name, parent_fd, basename, mode, expected_stat, True)
|
|
27211
|
+
def assert_expected_root(root_fd, payload):
|
|
27212
|
+
if "rootDev" in payload or "rootIno" in payload:
|
|
27213
|
+
root_stat = os.fstat(root_fd)
|
|
27214
|
+
if root_stat.st_dev != int(payload["rootDev"]) or root_stat.st_ino != int(payload["rootIno"]):
|
|
27215
|
+
raise RuntimeError("fs-safe-root-mismatch")
|
|
27129
27216
|
def stat_path(root_fd, payload):
|
|
27130
27217
|
relative = payload.get("relativePath", "")
|
|
27131
27218
|
segments = split_relative(relative)
|
|
@@ -27139,7 +27226,6 @@ def stat_path(root_fd, payload):
|
|
|
27139
27226
|
return encode_stat(st)
|
|
27140
27227
|
finally:
|
|
27141
27228
|
os.close(parent_fd)
|
|
27142
|
-
|
|
27143
27229
|
def readdir_path(root_fd, payload):
|
|
27144
27230
|
dir_fd = walk_dir(root_fd, split_relative(payload.get("relativePath", "")))
|
|
27145
27231
|
try:
|
|
@@ -27155,12 +27241,9 @@ def readdir_path(root_fd, payload):
|
|
|
27155
27241
|
return entries
|
|
27156
27242
|
finally:
|
|
27157
27243
|
os.close(dir_fd)
|
|
27158
|
-
|
|
27159
27244
|
def mkdirp_path(root_fd, payload):
|
|
27160
27245
|
dir_fd = walk_dir(root_fd, split_relative(payload.get("relativePath", "")), mkdir_enabled=True)
|
|
27161
|
-
os.close(dir_fd)
|
|
27162
|
-
return None
|
|
27163
|
-
|
|
27246
|
+
os.close(dir_fd); return None
|
|
27164
27247
|
def remove_tree(parent_fd, basename):
|
|
27165
27248
|
st = os.lstat(basename, dir_fd=parent_fd)
|
|
27166
27249
|
if stat.S_ISDIR(st.st_mode) and not stat.S_ISLNK(st.st_mode):
|
|
@@ -27173,7 +27256,6 @@ def remove_tree(parent_fd, basename):
|
|
|
27173
27256
|
os.rmdir(basename, dir_fd=parent_fd)
|
|
27174
27257
|
else:
|
|
27175
27258
|
os.unlink(basename, dir_fd=parent_fd)
|
|
27176
|
-
|
|
27177
27259
|
def remove_path(root_fd, payload):
|
|
27178
27260
|
parent_fd, basename = parent_and_basename(root_fd, payload.get("relativePath", ""))
|
|
27179
27261
|
try:
|
|
@@ -27200,7 +27282,18 @@ def rename_path(root_fd, payload):
|
|
|
27200
27282
|
try:
|
|
27201
27283
|
from_stat = os.lstat(from_base, dir_fd=from_parent_fd)
|
|
27202
27284
|
reject_unsafe_endpoint(from_stat)
|
|
27203
|
-
|
|
27285
|
+
overwrite = payload.get("overwrite", True)
|
|
27286
|
+
if not overwrite and stat.S_ISREG(from_stat.st_mode):
|
|
27287
|
+
try:
|
|
27288
|
+
link_no_replace(from_base, to_base, from_parent_fd, to_parent_fd)
|
|
27289
|
+
except OSError as exc:
|
|
27290
|
+
if not link_unsupported(exc):
|
|
27291
|
+
raise
|
|
27292
|
+
copy_file_no_replace(from_parent_fd, from_base, to_parent_fd, to_base, stat.S_IMODE(from_stat.st_mode), from_stat, True)
|
|
27293
|
+
return None
|
|
27294
|
+
if not overwrite and stat.S_ISDIR(from_stat.st_mode):
|
|
27295
|
+
raise RuntimeError("fs-safe-directory-noreplace-unsupported")
|
|
27296
|
+
if not overwrite:
|
|
27204
27297
|
try:
|
|
27205
27298
|
os.lstat(to_base, dir_fd=to_parent_fd)
|
|
27206
27299
|
raise FileExistsError(errno.EEXIST, "destination exists", to_base)
|
|
@@ -27245,19 +27338,15 @@ def write_path(root_fd, payload):
|
|
|
27245
27338
|
except FileNotFoundError:
|
|
27246
27339
|
pass
|
|
27247
27340
|
temp_name, temp_fd = create_temp_file(parent_fd, basename, mode)
|
|
27248
|
-
|
|
27249
|
-
|
|
27250
|
-
written = os.write(temp_fd, view)
|
|
27251
|
-
if written <= 0:
|
|
27252
|
-
raise OSError(errno.EIO, "short write")
|
|
27253
|
-
view = view[written:]
|
|
27341
|
+
os.fchmod(temp_fd, mode)
|
|
27342
|
+
write_all(temp_fd, data)
|
|
27254
27343
|
os.fsync(temp_fd)
|
|
27344
|
+
temp_stat = os.fstat(temp_fd)
|
|
27255
27345
|
os.close(temp_fd)
|
|
27256
27346
|
temp_fd = None
|
|
27257
|
-
|
|
27347
|
+
result_stat = commit_temp_file(parent_fd, temp_name, basename, overwrite, mode, temp_stat)
|
|
27258
27348
|
temp_name = None
|
|
27259
27349
|
os.fsync(parent_fd)
|
|
27260
|
-
result_stat = os.stat(basename, dir_fd=parent_fd, follow_symlinks=False)
|
|
27261
27350
|
return {"dev": result_stat.st_dev, "ino": result_stat.st_ino}
|
|
27262
27351
|
finally:
|
|
27263
27352
|
if temp_fd is not None:
|
|
@@ -27287,13 +27376,8 @@ def copy_path(root_fd, payload):
|
|
|
27287
27376
|
if max_bytes >= 0 and source_stat.st_size > max_bytes:
|
|
27288
27377
|
raise RuntimeError("fs-safe-too-large:%d:%d" % (max_bytes, source_stat.st_size))
|
|
27289
27378
|
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
27379
|
temp_name, temp_fd = create_temp_file(parent_fd, basename, mode)
|
|
27380
|
+
os.fchmod(temp_fd, mode)
|
|
27297
27381
|
written_bytes = 0
|
|
27298
27382
|
while True:
|
|
27299
27383
|
chunk = os.read(source_fd, 65536)
|
|
@@ -27309,12 +27393,12 @@ def copy_path(root_fd, payload):
|
|
|
27309
27393
|
raise OSError(errno.EIO, "short write")
|
|
27310
27394
|
view = view[written:]
|
|
27311
27395
|
os.fsync(temp_fd)
|
|
27396
|
+
temp_stat = os.fstat(temp_fd)
|
|
27312
27397
|
os.close(temp_fd)
|
|
27313
27398
|
temp_fd = None
|
|
27314
|
-
|
|
27399
|
+
result_stat = commit_temp_file(parent_fd, temp_name, basename, overwrite, mode, temp_stat)
|
|
27315
27400
|
temp_name = None
|
|
27316
27401
|
os.fsync(parent_fd)
|
|
27317
|
-
result_stat = os.stat(basename, dir_fd=parent_fd, follow_symlinks=False)
|
|
27318
27402
|
return {"dev": result_stat.st_dev, "ino": result_stat.st_ino}
|
|
27319
27403
|
finally:
|
|
27320
27404
|
os.close(source_fd)
|
|
@@ -27331,6 +27415,7 @@ def copy_path(root_fd, payload):
|
|
|
27331
27415
|
def run_operation(operation, root_path, payload):
|
|
27332
27416
|
root_fd = open_dir(root_path)
|
|
27333
27417
|
try:
|
|
27418
|
+
assert_expected_root(root_fd, payload)
|
|
27334
27419
|
if operation == "stat":
|
|
27335
27420
|
return stat_path(root_fd, payload)
|
|
27336
27421
|
if operation == "readdir":
|
|
@@ -27435,6 +27520,15 @@ function mapWorkerError(response) {
|
|
|
27435
27520
|
if (message.includes("fs-safe-source-mismatch")) {
|
|
27436
27521
|
return new errors_FsSafeError("path-mismatch", "source path changed during copy");
|
|
27437
27522
|
}
|
|
27523
|
+
if (message.includes("fs-safe-temp-mismatch")) {
|
|
27524
|
+
return new errors_FsSafeError("path-mismatch", "temp path changed during write");
|
|
27525
|
+
}
|
|
27526
|
+
if (message.includes("fs-safe-root-mismatch")) {
|
|
27527
|
+
return new errors_FsSafeError("path-mismatch", "root path changed during operation");
|
|
27528
|
+
}
|
|
27529
|
+
if (message.includes("fs-safe-directory-noreplace-unsupported")) {
|
|
27530
|
+
return new errors_FsSafeError("invalid-path", "directory moves require overwrite: true");
|
|
27531
|
+
}
|
|
27438
27532
|
if (code === "FileNotFoundError" || errno === 2) {
|
|
27439
27533
|
return new errors_FsSafeError("not-found", "file not found");
|
|
27440
27534
|
}
|
|
@@ -27452,19 +27546,19 @@ function mapWorkerError(response) {
|
|
|
27452
27546
|
}
|
|
27453
27547
|
return new errors_FsSafeError("helper-failed", message);
|
|
27454
27548
|
}
|
|
27455
|
-
function rejectPending(error) {
|
|
27456
|
-
if (!worker) {
|
|
27549
|
+
function rejectPending(error, targetWorker = worker) {
|
|
27550
|
+
if (!targetWorker || worker !== targetWorker) {
|
|
27457
27551
|
return;
|
|
27458
27552
|
}
|
|
27459
|
-
setWorkerRef(
|
|
27460
|
-
for (const pending of
|
|
27553
|
+
setWorkerRef(targetWorker, false);
|
|
27554
|
+
for (const pending of targetWorker.pending.values()) {
|
|
27461
27555
|
pending.reject(error);
|
|
27462
27556
|
}
|
|
27463
|
-
|
|
27557
|
+
targetWorker.pending.clear();
|
|
27464
27558
|
worker = null;
|
|
27465
27559
|
}
|
|
27466
|
-
function handleWorkerLine(line) {
|
|
27467
|
-
if (
|
|
27560
|
+
function handleWorkerLine(currentWorker, line) {
|
|
27561
|
+
if (worker !== currentWorker || !line.trim()) {
|
|
27468
27562
|
return;
|
|
27469
27563
|
}
|
|
27470
27564
|
let decoded;
|
|
@@ -27472,11 +27566,11 @@ function handleWorkerLine(line) {
|
|
|
27472
27566
|
decoded = JSON.parse(line);
|
|
27473
27567
|
}
|
|
27474
27568
|
catch {
|
|
27475
|
-
rejectPending(new errors_FsSafeError("helper-failed", `pinned helper returned invalid JSON: ${line}`));
|
|
27569
|
+
rejectPending(new errors_FsSafeError("helper-failed", `pinned helper returned invalid JSON: ${line}`), currentWorker);
|
|
27476
27570
|
return;
|
|
27477
27571
|
}
|
|
27478
27572
|
if (typeof decoded !== "object" || decoded === null || !("id" in decoded)) {
|
|
27479
|
-
rejectPending(new errors_FsSafeError("helper-failed", "pinned helper returned invalid response"));
|
|
27573
|
+
rejectPending(new errors_FsSafeError("helper-failed", "pinned helper returned invalid response"), currentWorker);
|
|
27480
27574
|
return;
|
|
27481
27575
|
}
|
|
27482
27576
|
const response = decoded;
|
|
@@ -27484,13 +27578,13 @@ function handleWorkerLine(line) {
|
|
|
27484
27578
|
if (id === undefined) {
|
|
27485
27579
|
return;
|
|
27486
27580
|
}
|
|
27487
|
-
const pending =
|
|
27581
|
+
const pending = currentWorker.pending.get(id);
|
|
27488
27582
|
if (!pending) {
|
|
27489
27583
|
return;
|
|
27490
27584
|
}
|
|
27491
|
-
|
|
27492
|
-
if (
|
|
27493
|
-
setWorkerRef(
|
|
27585
|
+
currentWorker.pending.delete(id);
|
|
27586
|
+
if (currentWorker.pending.size === 0) {
|
|
27587
|
+
setWorkerRef(currentWorker, false);
|
|
27494
27588
|
}
|
|
27495
27589
|
if (response.ok === true) {
|
|
27496
27590
|
pending.resolve(response.result);
|
|
@@ -27506,28 +27600,28 @@ function getWorker() {
|
|
|
27506
27600
|
const child = (0,external_node_child_process_.spawn)(resolvePython(), ["-u", "-c", PINNED_PYTHON_WORKER_SOURCE], {
|
|
27507
27601
|
stdio: ["pipe", "pipe", "pipe"],
|
|
27508
27602
|
});
|
|
27509
|
-
|
|
27603
|
+
const currentWorker = { child, pending: new Map(), stderr: "", stdoutBuffer: "" };
|
|
27604
|
+
worker = currentWorker;
|
|
27510
27605
|
child.stdout.setEncoding("utf8");
|
|
27511
27606
|
child.stderr.setEncoding("utf8");
|
|
27512
27607
|
child.stdout.on("data", (chunk) => {
|
|
27513
|
-
|
|
27514
|
-
if (!current) {
|
|
27608
|
+
if (worker !== currentWorker) {
|
|
27515
27609
|
return;
|
|
27516
27610
|
}
|
|
27517
|
-
|
|
27611
|
+
currentWorker.stdoutBuffer += chunk;
|
|
27518
27612
|
for (;;) {
|
|
27519
|
-
const newline =
|
|
27613
|
+
const newline = currentWorker.stdoutBuffer.indexOf("\n");
|
|
27520
27614
|
if (newline < 0) {
|
|
27521
27615
|
break;
|
|
27522
27616
|
}
|
|
27523
|
-
const line =
|
|
27524
|
-
|
|
27525
|
-
handleWorkerLine(line);
|
|
27617
|
+
const line = currentWorker.stdoutBuffer.slice(0, newline);
|
|
27618
|
+
currentWorker.stdoutBuffer = currentWorker.stdoutBuffer.slice(newline + 1);
|
|
27619
|
+
handleWorkerLine(currentWorker, line);
|
|
27526
27620
|
}
|
|
27527
27621
|
});
|
|
27528
27622
|
child.stderr.on("data", (chunk) => {
|
|
27529
|
-
if (worker) {
|
|
27530
|
-
|
|
27623
|
+
if (worker === currentWorker) {
|
|
27624
|
+
currentWorker.stderr = `${currentWorker.stderr}${chunk}`.slice(-4096);
|
|
27531
27625
|
}
|
|
27532
27626
|
});
|
|
27533
27627
|
child.once("error", (error) => {
|
|
@@ -27536,17 +27630,17 @@ function getWorker() {
|
|
|
27536
27630
|
: error instanceof Error
|
|
27537
27631
|
? error
|
|
27538
27632
|
: new Error(String(error));
|
|
27539
|
-
rejectPending(mapped);
|
|
27633
|
+
rejectPending(mapped, currentWorker);
|
|
27540
27634
|
});
|
|
27541
27635
|
child.once("close", (code, signal) => {
|
|
27542
|
-
const stderr =
|
|
27543
|
-
rejectPending(new errors_FsSafeError("helper-failed", stderr || `pinned helper exited with code ${code ?? "null"} (${signal ?? "?"})`));
|
|
27636
|
+
const stderr = currentWorker.stderr.trim();
|
|
27637
|
+
rejectPending(new errors_FsSafeError("helper-failed", stderr || `pinned helper exited with code ${code ?? "null"} (${signal ?? "?"})`), currentWorker);
|
|
27544
27638
|
});
|
|
27545
27639
|
process.once("exit", () => {
|
|
27546
27640
|
child.kill("SIGTERM");
|
|
27547
27641
|
});
|
|
27548
|
-
setWorkerRef(
|
|
27549
|
-
return
|
|
27642
|
+
setWorkerRef(currentWorker, false);
|
|
27643
|
+
return currentWorker;
|
|
27550
27644
|
}
|
|
27551
27645
|
function setRefable(value, ref) {
|
|
27552
27646
|
if (!value) {
|
|
@@ -27612,9 +27706,7 @@ function validatePinnedOperationPayload(payload) {
|
|
|
27612
27706
|
}
|
|
27613
27707
|
}
|
|
27614
27708
|
function isPinnedHelperUnavailable(error) {
|
|
27615
|
-
return error instanceof Error &&
|
|
27616
|
-
"code" in error &&
|
|
27617
|
-
error.code === "helper-unavailable";
|
|
27709
|
+
return error instanceof Error && "code" in error && error.code === "helper-unavailable";
|
|
27618
27710
|
}
|
|
27619
27711
|
function validatePinnedRelativePath(relativePath) {
|
|
27620
27712
|
if (relativePath.length === 0 || relativePath === ".") {
|
|
@@ -27712,29 +27804,21 @@ function assertWithinMaxBytes(bytes, maxBytes) {
|
|
|
27712
27804
|
throw new errors_FsSafeError("too-large", `file exceeds limit of ${maxBytes} bytes (got at least ${bytes})`);
|
|
27713
27805
|
}
|
|
27714
27806
|
}
|
|
27715
|
-
function
|
|
27716
|
-
if (maxBytes === undefined) {
|
|
27717
|
-
return undefined;
|
|
27718
|
-
}
|
|
27807
|
+
async function writeStreamToHandle(stream, handle, maxBytes) {
|
|
27719
27808
|
let bytes = 0;
|
|
27720
|
-
|
|
27721
|
-
|
|
27722
|
-
|
|
27723
|
-
|
|
27724
|
-
|
|
27725
|
-
|
|
27809
|
+
for await (const chunk of stream) {
|
|
27810
|
+
const buffer = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
|
|
27811
|
+
bytes += buffer.byteLength;
|
|
27812
|
+
assertWithinMaxBytes(bytes, maxBytes);
|
|
27813
|
+
let offset = 0;
|
|
27814
|
+
while (offset < buffer.byteLength) {
|
|
27815
|
+
const { bytesWritten } = await handle.write(buffer, offset, buffer.byteLength - offset);
|
|
27816
|
+
if (bytesWritten <= 0) {
|
|
27817
|
+
throw new errors_FsSafeError("helper-failed", "fallback stream write made no progress");
|
|
27726
27818
|
}
|
|
27727
|
-
|
|
27728
|
-
}
|
|
27729
|
-
});
|
|
27730
|
-
}
|
|
27731
|
-
async function pipelineWithMaxBytes(stream, destination, maxBytes) {
|
|
27732
|
-
const limiter = pinned_write_createMaxBytesTransform(maxBytes);
|
|
27733
|
-
if (limiter) {
|
|
27734
|
-
await (0,external_node_stream_promises_.pipeline)(stream, limiter, destination);
|
|
27735
|
-
return;
|
|
27819
|
+
offset += bytesWritten;
|
|
27820
|
+
}
|
|
27736
27821
|
}
|
|
27737
|
-
await (0,external_node_stream_promises_.pipeline)(stream, destination);
|
|
27738
27822
|
}
|
|
27739
27823
|
async function inputToBase64(input, maxBytes) {
|
|
27740
27824
|
if (input.kind === "buffer") {
|
|
@@ -27759,7 +27843,7 @@ async function runPinnedWriteHelper(params) {
|
|
|
27759
27843
|
relativeParentPath: params.relativeParentPath,
|
|
27760
27844
|
});
|
|
27761
27845
|
if (getFsSafePythonConfig().mode === "off") {
|
|
27762
|
-
return await
|
|
27846
|
+
return await runPinnedWriteFallbackOrThrow(params);
|
|
27763
27847
|
}
|
|
27764
27848
|
if (params.input.kind === "stream") {
|
|
27765
27849
|
try {
|
|
@@ -27767,7 +27851,7 @@ async function runPinnedWriteHelper(params) {
|
|
|
27767
27851
|
}
|
|
27768
27852
|
catch (error) {
|
|
27769
27853
|
if (canFallbackFromPythonError(error)) {
|
|
27770
|
-
return await
|
|
27854
|
+
return await runPinnedWriteFallbackOrThrow(params, error);
|
|
27771
27855
|
}
|
|
27772
27856
|
throw error;
|
|
27773
27857
|
}
|
|
@@ -27780,6 +27864,7 @@ async function runPinnedWriteHelper(params) {
|
|
|
27780
27864
|
mode: params.mode || 0o600,
|
|
27781
27865
|
overwrite: params.overwrite !== false,
|
|
27782
27866
|
relativeParentPath: params.relativeParentPath,
|
|
27867
|
+
...(params.rootIdentity ? { rootDev: params.rootIdentity.dev, rootIno: params.rootIdentity.ino } : {}),
|
|
27783
27868
|
};
|
|
27784
27869
|
try {
|
|
27785
27870
|
return await runPinnedPythonOperation({
|
|
@@ -27790,7 +27875,7 @@ async function runPinnedWriteHelper(params) {
|
|
|
27790
27875
|
}
|
|
27791
27876
|
catch (error) {
|
|
27792
27877
|
if (canFallbackFromPythonError(error)) {
|
|
27793
|
-
return await
|
|
27878
|
+
return await runPinnedWriteFallbackOrThrow(params, error);
|
|
27794
27879
|
}
|
|
27795
27880
|
throw error;
|
|
27796
27881
|
}
|
|
@@ -27810,22 +27895,29 @@ async function runPinnedCopyHelper(params) {
|
|
|
27810
27895
|
mode: params.mode || 0o600,
|
|
27811
27896
|
overwrite: params.overwrite !== false,
|
|
27812
27897
|
relativeParentPath: params.relativeParentPath,
|
|
27898
|
+
...(params.rootIdentity ? { rootDev: params.rootIdentity.dev, rootIno: params.rootIdentity.ino } : {}),
|
|
27813
27899
|
sourceDev: params.sourceIdentity.dev,
|
|
27814
27900
|
sourceIno: params.sourceIdentity.ino,
|
|
27815
27901
|
sourcePath: params.sourcePath,
|
|
27816
27902
|
},
|
|
27817
27903
|
});
|
|
27818
27904
|
}
|
|
27905
|
+
async function runPinnedWriteFallbackOrThrow(params, cause) {
|
|
27906
|
+
if (process.platform !== "win32") {
|
|
27907
|
+
throw new errors_FsSafeError("helper-unavailable", "Python helper is required for pinned writes on this platform", { cause });
|
|
27908
|
+
}
|
|
27909
|
+
return await runPinnedWriteFallback(params);
|
|
27910
|
+
}
|
|
27819
27911
|
async function runPinnedWriteFallback(params) {
|
|
27820
27912
|
const parentPath = params.relativeParentPath
|
|
27821
27913
|
? external_node_path_.join(params.rootPath, ...params.relativeParentPath.split("/"))
|
|
27822
27914
|
: params.rootPath;
|
|
27823
|
-
const parentGuard = await directory_guard_createNearestExistingDirectoryGuard(params.rootPath, parentPath);
|
|
27824
27915
|
if (params.mkdir) {
|
|
27825
|
-
await
|
|
27826
|
-
await promises_.mkdir(parentPath, { recursive: true });
|
|
27827
|
-
});
|
|
27916
|
+
await mkdirPathComponentsWithGuards({ rootReal: params.rootPath, targetPath: parentPath });
|
|
27828
27917
|
}
|
|
27918
|
+
const parentGuard = params.mkdir
|
|
27919
|
+
? await directory_guard_createAsyncDirectoryGuard(parentPath)
|
|
27920
|
+
: await directory_guard_createNearestExistingDirectoryGuard(params.rootPath, parentPath);
|
|
27829
27921
|
const targetPath = external_node_path_.join(parentPath, params.basename);
|
|
27830
27922
|
if (params.overwrite === false) {
|
|
27831
27923
|
let handle = await withAsyncDirectoryGuards([parentGuard], async () => await promises_.open(targetPath, external_node_fs_.constants.O_WRONLY | external_node_fs_.constants.O_CREAT | external_node_fs_.constants.O_EXCL, params.mode), {
|
|
@@ -27847,7 +27939,7 @@ async function runPinnedWriteFallback(params) {
|
|
|
27847
27939
|
}
|
|
27848
27940
|
}
|
|
27849
27941
|
else {
|
|
27850
|
-
await
|
|
27942
|
+
await writeStreamToHandle(params.input.stream, handle, params.maxBytes);
|
|
27851
27943
|
}
|
|
27852
27944
|
const stat = await handle.stat();
|
|
27853
27945
|
created = false;
|
|
@@ -27868,7 +27960,9 @@ async function runPinnedWriteFallback(params) {
|
|
|
27868
27960
|
? external_node_fs_.constants.O_NOFOLLOW
|
|
27869
27961
|
: 0);
|
|
27870
27962
|
let handle;
|
|
27871
|
-
let
|
|
27963
|
+
let tempStat;
|
|
27964
|
+
let targetStat;
|
|
27965
|
+
let renamed = false;
|
|
27872
27966
|
try {
|
|
27873
27967
|
handle = await promises_.open(tempPath, tempFlags, params.mode);
|
|
27874
27968
|
if (params.input.kind === "buffer") {
|
|
@@ -27881,29 +27975,36 @@ async function runPinnedWriteFallback(params) {
|
|
|
27881
27975
|
}
|
|
27882
27976
|
}
|
|
27883
27977
|
else {
|
|
27884
|
-
|
|
27885
|
-
writable.once("close", () => {
|
|
27886
|
-
handleClosedByStream = true;
|
|
27887
|
-
});
|
|
27888
|
-
await pipelineWithMaxBytes(params.input.stream, writable, params.maxBytes);
|
|
27978
|
+
await writeStreamToHandle(params.input.stream, handle, params.maxBytes);
|
|
27889
27979
|
}
|
|
27890
|
-
|
|
27891
|
-
|
|
27892
|
-
|
|
27980
|
+
tempStat = await handle.stat();
|
|
27981
|
+
const tempPathStat = await promises_.lstat(tempPath);
|
|
27982
|
+
if (tempPathStat.isSymbolicLink() || !file_identity_sameFileIdentity(tempPathStat, tempStat)) {
|
|
27983
|
+
throw new errors_FsSafeError("path-mismatch", "fallback temp path changed during write");
|
|
27893
27984
|
}
|
|
27985
|
+
const expectedTempStat = tempStat;
|
|
27986
|
+
await handle.close().catch(() => undefined);
|
|
27987
|
+
handle = undefined;
|
|
27894
27988
|
await withAsyncDirectoryGuards([parentGuard], async () => {
|
|
27895
27989
|
await promises_.rename(tempPath, targetPath);
|
|
27990
|
+
renamed = true;
|
|
27991
|
+
targetStat = await promises_.lstat(targetPath);
|
|
27992
|
+
if (targetStat.isSymbolicLink() || !file_identity_sameFileIdentity(targetStat, expectedTempStat)) {
|
|
27993
|
+
throw new errors_FsSafeError("path-mismatch", "fallback target changed during write");
|
|
27994
|
+
}
|
|
27896
27995
|
});
|
|
27897
27996
|
}
|
|
27898
27997
|
catch (error) {
|
|
27899
|
-
|
|
27900
|
-
|
|
27998
|
+
await handle?.close().catch(() => undefined);
|
|
27999
|
+
if (!renamed) {
|
|
28000
|
+
await promises_.rm(tempPath, { force: true }).catch(() => undefined);
|
|
27901
28001
|
}
|
|
27902
|
-
await promises_.rm(tempPath, { force: true }).catch(() => undefined);
|
|
27903
28002
|
throw error;
|
|
27904
28003
|
}
|
|
27905
|
-
|
|
27906
|
-
|
|
28004
|
+
if (!targetStat) {
|
|
28005
|
+
throw new errors_FsSafeError("path-mismatch", "fallback target was not verified");
|
|
28006
|
+
}
|
|
28007
|
+
return { dev: targetStat.dev, ino: targetStat.ino };
|
|
27907
28008
|
}
|
|
27908
28009
|
|
|
27909
28010
|
// EXTERNAL MODULE: external "node:os"
|
|
@@ -28442,7 +28543,7 @@ function relativeInsideRoot(rootPath, targetPath) {
|
|
|
28442
28543
|
if (!relative || relative === ".") {
|
|
28443
28544
|
return "";
|
|
28444
28545
|
}
|
|
28445
|
-
if (
|
|
28546
|
+
if (isPathRelativeEscape(relative)) {
|
|
28446
28547
|
return "";
|
|
28447
28548
|
}
|
|
28448
28549
|
return relative;
|
|
@@ -28793,6 +28894,15 @@ function __setFsSafeTestHooksForTest(hooks) {
|
|
|
28793
28894
|
test_hooks_fsSafeTestHooks = hooks;
|
|
28794
28895
|
}
|
|
28795
28896
|
|
|
28897
|
+
;// CONCATENATED MODULE: ../../node_modules/@openclaw/fs-safe/dist/json-stringify.js
|
|
28898
|
+
function stringifyJsonDocument(value, replacer, space) {
|
|
28899
|
+
const text = JSON.stringify(value, replacer, space);
|
|
28900
|
+
if (typeof text !== "string") {
|
|
28901
|
+
throw new TypeError("value is not representable as a JSON document");
|
|
28902
|
+
}
|
|
28903
|
+
return text;
|
|
28904
|
+
}
|
|
28905
|
+
|
|
28796
28906
|
;// CONCATENATED MODULE: ../../node_modules/@openclaw/fs-safe/dist/temp-cleanup.js
|
|
28797
28907
|
|
|
28798
28908
|
const tempCleanupEntries = new Map();
|
|
@@ -28880,6 +28990,7 @@ async function serializePathWrite(key, run) {
|
|
|
28880
28990
|
|
|
28881
28991
|
|
|
28882
28992
|
|
|
28993
|
+
|
|
28883
28994
|
|
|
28884
28995
|
|
|
28885
28996
|
function logWarn(message) {
|
|
@@ -29120,12 +29231,12 @@ class RootHandle {
|
|
|
29120
29231
|
}
|
|
29121
29232
|
async writeJson(relativePath, data, options = {}) {
|
|
29122
29233
|
const { replacer, space, trailingNewline = true, ...writeOptions } = options;
|
|
29123
|
-
const json =
|
|
29234
|
+
const json = stringifyJsonDocument(data, replacer, space);
|
|
29124
29235
|
await this.write(relativePath, trailingNewline ? `${json}\n` : json, writeOptions);
|
|
29125
29236
|
}
|
|
29126
29237
|
async createJson(relativePath, data, options = {}) {
|
|
29127
29238
|
const { replacer, space, trailingNewline = true, ...writeOptions } = options;
|
|
29128
|
-
const json =
|
|
29239
|
+
const json = stringifyJsonDocument(data, replacer, space);
|
|
29129
29240
|
await this.create(relativePath, trailingNewline ? `${json}\n` : json, writeOptions);
|
|
29130
29241
|
}
|
|
29131
29242
|
async copyIn(relativePath, sourcePath, options = {}) {
|
|
@@ -29910,6 +30021,9 @@ async function movePathFallback(root, params) {
|
|
|
29910
30021
|
if (sourceStat.isFile() && sourceStat.nlink > 1) {
|
|
29911
30022
|
throw new errors_FsSafeError("hardlink", "hardlinked path not allowed");
|
|
29912
30023
|
}
|
|
30024
|
+
if (!params.overwrite && sourceStat.isDirectory()) {
|
|
30025
|
+
throw new errors_FsSafeError("invalid-path", "directory moves require overwrite: true");
|
|
30026
|
+
}
|
|
29913
30027
|
if (!params.overwrite) {
|
|
29914
30028
|
try {
|
|
29915
30029
|
await promises_.lstat(target.resolved);
|
|
@@ -68063,4 +68177,4 @@ if (installedChunkData !== 0) { // 0 means "already installed".'
|
|
|
68063
68177
|
// module factories are used so entry inlining is disabled
|
|
68064
68178
|
// startup
|
|
68065
68179
|
// Load entry module and return exports
|
|
68066
|
-
var __webpack_exports__ = __webpack_require__(
|
|
68180
|
+
var __webpack_exports__ = __webpack_require__(3523);
|