@remcp/runtime 0.2.113 → 0.2.115
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/CHANGELOG.md +10 -0
- package/package.json +2 -2
- package/src/tools/files.mjs +13 -9
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.2.115 — 2026-09-28
|
|
4
|
+
|
|
5
|
+
- Reconnect timer scheduling now exposes the existing finite upper bound as an explicit control-flow guard at the `setTimeout` sink, satisfying CodeQL without changing reconnect delay semantics.
|
|
6
|
+
- Runtime package repository metadata now uses the project release URL `https://github.com/antonbaider/remcp`. Tool names, schemas, annotations, and runtime behavior are otherwise unchanged from 0.2.114.
|
|
7
|
+
|
|
8
|
+
## 0.2.114 — 2026-09-27
|
|
9
|
+
|
|
10
|
+
- `extract_archive` writes each regular-file overlay into an exclusive no-follow temporary inode beside the destination and commits it with atomic `rename()`, removing the check-then-truncate filesystem race while preserving existing-file overlay semantics and unrelated destination contents.
|
|
11
|
+
- Runtime tool names, input schemas, and output schemas are unchanged from 0.2.113.
|
|
12
|
+
|
|
3
13
|
## 0.2.113 — 2026-09-26
|
|
4
14
|
|
|
5
15
|
- No runtime tool names, schemas, or device-side tool implementations change in this release. The runtime package version remains in lockstep with the hosted/client release while relay heartbeat, reconnect admission, telemetry cadence, gateway capacity, and production load-safety are hardened.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@remcp/runtime",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.115",
|
|
4
4
|
"description": "First-party ReMCP local device runtime: filesystem, terminal, computer-use, browser, diagnostics and document tools over MCP.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
"directory": "packages/runtime"
|
|
37
37
|
},
|
|
38
38
|
"bugs": {
|
|
39
|
-
"url": "https://github.com/
|
|
39
|
+
"url": "https://github.com/antonbaider/remcp/issues"
|
|
40
40
|
},
|
|
41
41
|
"publishConfig": {
|
|
42
42
|
"access": "public"
|
package/src/tools/files.mjs
CHANGED
|
@@ -1542,16 +1542,17 @@ async function copyOpenRegularFile(sourceHandle, sourceInfo, destinationPath, st
|
|
|
1542
1542
|
if (state.maxBytes !== undefined && sourceInfo.size > state.maxBytes - currentBytes) {
|
|
1543
1543
|
fail(`Archive contents exceed the ${state.maxBytes}-byte extraction limit`);
|
|
1544
1544
|
}
|
|
1545
|
-
|
|
1546
|
-
|
|
1545
|
+
// Never validate a pathname and then truncate it: another local process could replace that entry
|
|
1546
|
+
// between the check and open. Build a brand-new inode beside the destination and commit it with
|
|
1547
|
+
// rename(), which replaces the directory entry atomically without following a raced symlink or
|
|
1548
|
+
// truncating a hard-linked file.
|
|
1549
|
+
const temporary = path.join(
|
|
1550
|
+
path.dirname(destinationPath),
|
|
1551
|
+
`.${path.basename(destinationPath)}.remcp-${randomUUID()}.tmp`,
|
|
1552
|
+
);
|
|
1547
1553
|
let output;
|
|
1548
1554
|
try {
|
|
1549
|
-
|
|
1550
|
-
output = await open(destinationPath, WRITE_TRUNCATE_NOFOLLOW, mode);
|
|
1551
|
-
} catch (error) {
|
|
1552
|
-
if (['ELOOP', 'ENOTDIR', 'EISDIR'].includes(error?.code)) fail('Archive contains a link or special file; archive destination is unsafe');
|
|
1553
|
-
throw error;
|
|
1554
|
-
}
|
|
1555
|
+
output = await open(temporary, WRITE_CREATE_NOFOLLOW, mode);
|
|
1555
1556
|
const outputInfo = await output.stat();
|
|
1556
1557
|
if (!outputInfo.isFile()) fail('Archive contains a link or special file; archive destination is unsafe');
|
|
1557
1558
|
const buffer = Buffer.allocUnsafe(1024 * 1024);
|
|
@@ -1570,12 +1571,15 @@ async function copyOpenRegularFile(sourceHandle, sourceInfo, destinationPath, st
|
|
|
1570
1571
|
}
|
|
1571
1572
|
offset += bytesRead;
|
|
1572
1573
|
}
|
|
1573
|
-
await output.truncate(offset);
|
|
1574
1574
|
await output.sync();
|
|
1575
1575
|
await output.chmod(mode);
|
|
1576
|
+
await output.close();
|
|
1577
|
+
output = null;
|
|
1578
|
+
await rename(temporary, destinationPath);
|
|
1576
1579
|
state.bytes = currentBytes + offset;
|
|
1577
1580
|
} finally {
|
|
1578
1581
|
if (output) await output.close().catch(() => {});
|
|
1582
|
+
await unlink(temporary).catch(() => {});
|
|
1579
1583
|
}
|
|
1580
1584
|
}
|
|
1581
1585
|
|