zames_pro 2.80.1 → 2.80.3
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 +13 -0
- package/dist/input/layout.js +38 -12
- package/dist/undo.js +10 -6
- package/dist/web.js +11 -2
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,19 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [2.80.3] - 2026-10-20
|
|
11
|
+
|
|
12
|
+
### Fixed
|
|
13
|
+
|
|
14
|
+
- a malformed uddg escape does not abort the web search
|
|
15
|
+
|
|
16
|
+
## [2.80.2] - 2026-10-20
|
|
17
|
+
|
|
18
|
+
### Fixed
|
|
19
|
+
|
|
20
|
+
- wrapToWidth keeps the indentation and inner spaces of a line
|
|
21
|
+
- **undo:** derive the backup name hash with sha1 instead of a path prefix
|
|
22
|
+
|
|
10
23
|
## [2.80.1] - 2026-10-20
|
|
11
24
|
|
|
12
25
|
### Fixed
|
package/dist/input/layout.js
CHANGED
|
@@ -183,41 +183,67 @@ export function wrapToWidth(s, maxCols) {
|
|
|
183
183
|
out.push('');
|
|
184
184
|
continue;
|
|
185
185
|
}
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
186
|
+
// A line that already fits is returned VERBATIM: wrapping is a width
|
|
187
|
+
// operation, not a normalizer. Splitting on spaces and re-joining ate the
|
|
188
|
+
// leading indentation (and emptied a line of only spaces), so an indented
|
|
189
|
+
// warning / echoed operator line lost its layout.
|
|
190
|
+
if (visLen(raw) <= width) {
|
|
191
|
+
out.push(raw);
|
|
192
|
+
continue;
|
|
193
|
+
}
|
|
194
|
+
// Wrapping is a WIDTH operation, not a normalizer: the spaces BETWEEN words
|
|
195
|
+
// (and the leading indentation) belong to the line and are reproduced
|
|
196
|
+
// verbatim. The old split(' ')/join(' ') glued the words back with ONE
|
|
197
|
+
// separator, so `'aaa bbb'` at width 7 became `'aaabbb'` and an indented
|
|
198
|
+
// warning lost its indent.
|
|
199
|
+
const words = raw.split(/ +/).filter((w) => w !== '');
|
|
200
|
+
const indent = raw.slice(0, raw.length - raw.trimStart().length);
|
|
201
|
+
let line = indent;
|
|
202
|
+
let lineW = visLen(indent);
|
|
203
|
+
let first = true;
|
|
204
|
+
for (let i = 0; i < words.length; i++) {
|
|
205
|
+
const word = words[i];
|
|
189
206
|
const w = visLen(word);
|
|
190
207
|
// Hard-split a word longer than a whole line.
|
|
191
208
|
if (w > width) {
|
|
192
|
-
if (
|
|
209
|
+
if (!first) {
|
|
193
210
|
out.push(line);
|
|
211
|
+
line = '';
|
|
212
|
+
lineW = 0;
|
|
194
213
|
}
|
|
195
214
|
let piece = '';
|
|
196
215
|
let pieceW = 0;
|
|
197
216
|
for (const ch of word) {
|
|
198
217
|
const cw = charWidth(ch.codePointAt(0));
|
|
199
218
|
if (pieceW + cw > width) {
|
|
200
|
-
out.push(piece);
|
|
219
|
+
out.push(line + piece);
|
|
220
|
+
line = '';
|
|
221
|
+
lineW = 0;
|
|
201
222
|
piece = '';
|
|
202
223
|
pieceW = 0;
|
|
203
224
|
}
|
|
204
225
|
piece += ch;
|
|
205
226
|
pieceW += cw;
|
|
206
227
|
}
|
|
207
|
-
line
|
|
208
|
-
lineW
|
|
228
|
+
line += piece;
|
|
229
|
+
lineW += pieceW;
|
|
230
|
+
first = false;
|
|
209
231
|
continue;
|
|
210
232
|
}
|
|
211
|
-
|
|
212
|
-
if (lineW + sep + w > width) {
|
|
233
|
+
if (!first && lineW + 1 + w > width) {
|
|
213
234
|
out.push(line);
|
|
214
235
|
line = word;
|
|
215
236
|
lineW = w;
|
|
237
|
+
first = false;
|
|
238
|
+
continue;
|
|
216
239
|
}
|
|
217
|
-
|
|
218
|
-
line
|
|
219
|
-
lineW +=
|
|
240
|
+
if (!first) {
|
|
241
|
+
line += ' ';
|
|
242
|
+
lineW += 1;
|
|
220
243
|
}
|
|
244
|
+
line += word;
|
|
245
|
+
lineW += w;
|
|
246
|
+
first = false;
|
|
221
247
|
}
|
|
222
248
|
out.push(line);
|
|
223
249
|
}
|
package/dist/undo.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import fs from 'fs/promises';
|
|
2
2
|
import path from 'path';
|
|
3
3
|
import os from 'os';
|
|
4
|
-
import { randomBytes } from 'crypto';
|
|
4
|
+
import { randomBytes, createHash } from 'crypto';
|
|
5
5
|
import { writeJsonAtomic } from './fsutil.js';
|
|
6
6
|
const UNDO_DIR = path.join(os.homedir(), '.zames', 'undo');
|
|
7
7
|
const INDEX = path.join(UNDO_DIR, 'index.json');
|
|
@@ -42,13 +42,17 @@ export class UndoStore {
|
|
|
42
42
|
throw e;
|
|
43
43
|
}
|
|
44
44
|
const stamp = Date.now();
|
|
45
|
-
|
|
45
|
+
// The name only needs to be SHORT and unique; the backup name also
|
|
46
|
+
// carries a random suffix. A 16-hex prefix of the hex-encoded path is
|
|
47
|
+
// the first 8 BYTES of the path, which for files in one directory is
|
|
48
|
+
// the SAME string (and identical without the random part).
|
|
49
|
+
const hash = createHash('sha1').update(filePath).digest('hex').slice(0, 16);
|
|
46
50
|
let backupFile = null;
|
|
47
51
|
if (existed) {
|
|
48
|
-
// The stamp is only ms-precision
|
|
49
|
-
//
|
|
50
|
-
//
|
|
51
|
-
// backup
|
|
52
|
+
// The stamp is only ms-precision, so two edits in the same
|
|
53
|
+
// millisecond would share a backup name and the second write would
|
|
54
|
+
// clobber the first (losing the backup). Add a random suffix so a
|
|
55
|
+
// backup name is unique.
|
|
52
56
|
const uniq = randomBytes(4).toString('hex');
|
|
53
57
|
backupFile = path.join(UNDO_DIR, `${stamp}-${hash}-${uniq}.bak`);
|
|
54
58
|
await fs.writeFile(backupFile, content);
|
package/dist/web.js
CHANGED
|
@@ -643,8 +643,17 @@ export function parseDuckDuckGoResults(body, limit) {
|
|
|
643
643
|
while ((m = re.exec(body)) && results.length < limit) {
|
|
644
644
|
let href = m[1];
|
|
645
645
|
const uddgMatch = href.match(/[?&]uddg=([^&]+)/);
|
|
646
|
-
if (uddgMatch)
|
|
647
|
-
|
|
646
|
+
if (uddgMatch) {
|
|
647
|
+
// decodeURIComponent THROWS on a malformed percent escape (`%ZZ`, a lone
|
|
648
|
+
// `%`). One broken href in the page must not abort the whole search: keep
|
|
649
|
+
// the raw href, which the http(s) check below then rejects.
|
|
650
|
+
try {
|
|
651
|
+
href = decodeURIComponent(uddgMatch[1]);
|
|
652
|
+
}
|
|
653
|
+
catch {
|
|
654
|
+
href = uddgMatch[1];
|
|
655
|
+
}
|
|
656
|
+
}
|
|
648
657
|
const title = htmlToText(m[2] || '').trim();
|
|
649
658
|
const snippet = htmlToText(m[3] || '').trim();
|
|
650
659
|
// Only an absolute http(s) link is a real result. The page can carry a
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "zames_pro",
|
|
3
|
-
"version": "2.80.
|
|
3
|
+
"version": "2.80.3",
|
|
4
4
|
"description": "Terminal coding agent that drives a real browser to chat with DeepSeek, Qwen and other web LLMs — 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": {
|