zames_pro 2.90.12 → 2.90.14
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 +12 -0
- package/dist/extraTools.js +9 -1
- package/dist/shell.js +42 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [2.90.14] - 2026-10-29
|
|
11
|
+
|
|
12
|
+
### Fixed
|
|
13
|
+
|
|
14
|
+
- **sandbox:** block a recursive rm of an absolute or outside path
|
|
15
|
+
|
|
16
|
+
## [2.90.13] - 2026-10-29
|
|
17
|
+
|
|
18
|
+
### Fixed
|
|
19
|
+
|
|
20
|
+
- **apply-patch:** start each hunk search where the previous one ended
|
|
21
|
+
|
|
10
22
|
## [2.90.12] - 2026-10-29
|
|
11
23
|
|
|
12
24
|
### Fixed
|
package/dist/extraTools.js
CHANGED
|
@@ -168,6 +168,11 @@ export function applyUpdateHunk(content, hunkLines) {
|
|
|
168
168
|
const hasCRLF = content.includes('\r\n');
|
|
169
169
|
const eol = hasCRLF ? '\r\n' : NL;
|
|
170
170
|
let fileLines = content.split(/\r?\n/);
|
|
171
|
+
// Hunks are ordered top-to-bottom, so the search for the next block must not
|
|
172
|
+
// go back before the end of the previous one. Searching from 0 made a hunk
|
|
173
|
+
// re-find a region an EARLIER hunk had already consumed (or, once that text
|
|
174
|
+
// was gone, fail with "Context not found").
|
|
175
|
+
let searchFrom = 0;
|
|
171
176
|
for (const block of splitHunks(hunkLines)) {
|
|
172
177
|
const oldLines = [];
|
|
173
178
|
const newLines = [];
|
|
@@ -198,7 +203,7 @@ export function applyUpdateHunk(content, hunkLines) {
|
|
|
198
203
|
error: 'Hunk has no context or removed lines to anchor on.',
|
|
199
204
|
};
|
|
200
205
|
}
|
|
201
|
-
const at = locateBlock(fileLines, oldLines, block.oldStart,
|
|
206
|
+
const at = locateBlock(fileLines, oldLines, block.oldStart, searchFrom);
|
|
202
207
|
if (at === -1) {
|
|
203
208
|
return {
|
|
204
209
|
ok: false,
|
|
@@ -211,6 +216,9 @@ export function applyUpdateHunk(content, hunkLines) {
|
|
|
211
216
|
...newLines,
|
|
212
217
|
...fileLines.slice(at + oldLines.length),
|
|
213
218
|
];
|
|
219
|
+
// The next block starts after the lines this hunk just produced: its text
|
|
220
|
+
// cannot legitimately live BEFORE them.
|
|
221
|
+
searchFrom = at + newLines.length;
|
|
214
222
|
}
|
|
215
223
|
return { ok: true, content: fileLines.join(eol) };
|
|
216
224
|
}
|
package/dist/shell.js
CHANGED
|
@@ -70,6 +70,48 @@ export function assertCommandInsideRoot(root, command) {
|
|
|
70
70
|
if (/\bchroot\b/i.test(cmd)) {
|
|
71
71
|
throw new Error('Sandbox: chroot is forbidden');
|
|
72
72
|
}
|
|
73
|
+
// A RECURSIVE deletion aimed at an absolute path, `~`, `.`, `..` or the root
|
|
74
|
+
// itself can never be "inside the root": a single typo in a cleanup command
|
|
75
|
+
// destroyed the whole project tree (and the directories above it) in a real
|
|
76
|
+
// session. Only the destructive form is refused — `rm file.txt` and
|
|
77
|
+
// `rm -rf tmp/build` stay allowed.
|
|
78
|
+
const rmRe = /(?:^|[;&|(]\s*)\s*(?:sudo\s+)?rm\s+([^;&|)]+)/gi;
|
|
79
|
+
let rm;
|
|
80
|
+
while ((rm = rmRe.exec(cmd))) {
|
|
81
|
+
const words = rm[1].trim().split(/\s+/);
|
|
82
|
+
const recursive = words.some((w) => w === '--recursive' || /^-[a-zA-Z]*[rR][a-zA-Z]*$/.test(w));
|
|
83
|
+
if (!recursive)
|
|
84
|
+
continue;
|
|
85
|
+
for (const w of words) {
|
|
86
|
+
if (w.startsWith('-'))
|
|
87
|
+
continue;
|
|
88
|
+
const raw = w.replace(/["']/g, '');
|
|
89
|
+
if (!raw)
|
|
90
|
+
continue;
|
|
91
|
+
if (raw === '/' ||
|
|
92
|
+
raw === '.' ||
|
|
93
|
+
raw === '..' ||
|
|
94
|
+
raw === '~' ||
|
|
95
|
+
raw.startsWith('~/') ||
|
|
96
|
+
raw.startsWith('/') ||
|
|
97
|
+
raw.startsWith('..')) {
|
|
98
|
+
throw new Error('Sandbox: recursive rm of an absolute/outside path is forbidden (' +
|
|
99
|
+
raw +
|
|
100
|
+
')');
|
|
101
|
+
}
|
|
102
|
+
// A RELATIVE target is resolved against the root; anything that escapes
|
|
103
|
+
// (a `../` inside a longer path) is refused too.
|
|
104
|
+
const target = path.resolve(root, raw);
|
|
105
|
+
const rel = path.relative(root, target);
|
|
106
|
+
if (rel.startsWith('..') || path.isAbsolute(rel)) {
|
|
107
|
+
throw new Error('Sandbox: recursive rm outside ' +
|
|
108
|
+
root +
|
|
109
|
+
' is forbidden (' +
|
|
110
|
+
raw +
|
|
111
|
+
')');
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
73
115
|
}
|
|
74
116
|
function formatExecResult(err, stdout, stderr, timeout, okExitCodes) {
|
|
75
117
|
const out = (stdout || '').toString();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "zames_pro",
|
|
3
|
-
"version": "2.90.
|
|
3
|
+
"version": "2.90.14",
|
|
4
4
|
"description": "Terminal coding agent that drives a real browser to chat with DeepSeek, Qwen or GLM — no API key required. Reads and edits files, runs commands, commits to git, like Claude Code / Codex CLI.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|