zames_pro 2.82.66 → 2.82.68
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/tools.js +30 -3
- package/dist/tui/edit.js +27 -4
- 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.82.68] - 2026-10-24
|
|
11
|
+
|
|
12
|
+
### Fixed
|
|
13
|
+
|
|
14
|
+
- **tools:** do not drop read-only MCP tools from plan mode
|
|
15
|
+
|
|
16
|
+
## [2.82.67] - 2026-10-24
|
|
17
|
+
|
|
18
|
+
### Fixed
|
|
19
|
+
|
|
20
|
+
- **tui:** Up/Down in a wrapped input keeps the visual column
|
|
21
|
+
|
|
10
22
|
## [2.82.66] - 2026-10-24
|
|
11
23
|
|
|
12
24
|
### Fixed
|
package/dist/tools.js
CHANGED
|
@@ -479,6 +479,10 @@ const MCP_MUTATING_WORDS = new Set(('click type navigate press upload select dra
|
|
|
479
479
|
// Multi-word verbs are matched as a substring of the normalized name: they
|
|
480
480
|
// never stand alone as ONE `_word_`, so a word-set alone missed them.
|
|
481
481
|
const MCP_MUTATING_PHRASES = ['run_code', 'run_', 'handle_dialog'];
|
|
482
|
+
// Read-only SCOPES that legitimately prefix a verb-like word (`read_...`,
|
|
483
|
+
// `get_...`, `list_...`, `describe_...`): a name like `read_insert_log` is a
|
|
484
|
+
// read action on a log, not an insert. A writer never puts these first.
|
|
485
|
+
const MCP_READ_SCOPES = new Set(['read', 'get', 'list', 'describe', 'fetch']);
|
|
482
486
|
// A camelCase name is split BEFORE it is lowercased: `browserClick` used to
|
|
483
487
|
// become `browserclick` (one word, no verb) and slipped through read-only mode.
|
|
484
488
|
function splitCamelCase(s) {
|
|
@@ -494,12 +498,35 @@ export function isMutatingMcpTool(name) {
|
|
|
494
498
|
if (MCP_MUTATING_PHRASES.some((p) => norm.includes(p)))
|
|
495
499
|
return true;
|
|
496
500
|
const words = norm.split('_').filter(Boolean);
|
|
501
|
+
// A read SCOPE (`read_…`, `get_…`) makes the whole name a READ even when a
|
|
502
|
+
// verb-like word follows: `describe_type` describes a type,
|
|
503
|
+
// `read_insert_log` reads a log. Dropping them from plan mode removed a tool
|
|
504
|
+
// the model may use. Checked BEFORE the word match, so the scope word wins.
|
|
505
|
+
if (MCP_READ_SCOPES.has(words[0]))
|
|
506
|
+
return false;
|
|
497
507
|
if (words.some((w) => MCP_MUTATING_WORDS.has(w)))
|
|
498
508
|
return true;
|
|
499
509
|
// A CONCATENATED style (all lowercase, no separator: `browserclick`,
|
|
500
|
-
// `pageevaluate`) still hides a writer. A
|
|
501
|
-
//
|
|
502
|
-
|
|
510
|
+
// `pageevaluate`) still hides a writer. A BARE substring test is too
|
|
511
|
+
// aggressive, though: `get_settings` contains `set`, `get_keywords`
|
|
512
|
+
// contains `key`, `read_insert_log` contains `insert`, `describe_type`
|
|
513
|
+
// contains `type` — genuine READ-ONLY tools were dropped from plan mode.
|
|
514
|
+
// A concatenated verb is only trusted when it is a PREFIX of the name
|
|
515
|
+
// (`browserclick` -> after the `browser` scope) or spans the WHOLE name
|
|
516
|
+
// (`pageevaluate`); a verb buried inside another word is not an action.
|
|
517
|
+
const compact = norm.replace(/_/g, '');
|
|
518
|
+
const lastWord = words[words.length - 1];
|
|
519
|
+
return [...MCP_MUTATING_WORDS].some((v) => {
|
|
520
|
+
if (lastWord === v)
|
|
521
|
+
return true;
|
|
522
|
+
// A concatenated writer glues the verb to a SCOPE word: `fileupload`,
|
|
523
|
+
// `mouseclick`, `codeexecute`. Only the scope+verb pair counts — a bare
|
|
524
|
+
// word that merely CONTAINS the letters (`readinsertlog`,
|
|
525
|
+
// `describetype`) is a read action on a thing, not a write.
|
|
526
|
+
if (!compact.endsWith(v) || compact === v)
|
|
527
|
+
return false;
|
|
528
|
+
return !MCP_READ_SCOPES.has(compact.slice(0, -v.length));
|
|
529
|
+
});
|
|
503
530
|
}
|
|
504
531
|
// Merge MCP tools into the base set. In read-only (plan) mode the MCP tools
|
|
505
532
|
// must be filtered too: an MCP server (e.g. @playwright/mcp) exposes mutating
|
package/dist/tui/edit.js
CHANGED
|
@@ -177,14 +177,37 @@ export function moveVisualRows(s, delta, promptStr, cols) {
|
|
|
177
177
|
return s;
|
|
178
178
|
const row = lay.rows[target];
|
|
179
179
|
const rowChars = Array.from(row.text);
|
|
180
|
-
|
|
181
|
-
|
|
180
|
+
// `cursorCol` is the column inside the CURRENT row (prompt + its text). The
|
|
181
|
+
// row above/below has a DIFFERENT indent (`row.start` differs), so the
|
|
182
|
+
// offset must be measured from the CURRENT row's own text, not as a raw
|
|
183
|
+
// `cursorCol - promptW` character count: on a wrapped line that put the
|
|
184
|
+
// caret past the target row's text and onto the NEXT row entirely.
|
|
185
|
+
const curRow = lay.rows[lay.cursorRow];
|
|
186
|
+
const curChars = Array.from(curRow.text);
|
|
187
|
+
let want = 0;
|
|
188
|
+
for (let k = 0; k < lay.cursorCol - visLen(curRow.prefix); k++) {
|
|
189
|
+
want += charWidth(curChars[k]?.codePointAt(0) ?? 32);
|
|
190
|
+
}
|
|
182
191
|
let idx = row.start;
|
|
183
192
|
let w = 0;
|
|
184
|
-
|
|
185
|
-
|
|
193
|
+
// Walk the target row and STOP on the first character that no longer fits.
|
|
194
|
+
// Landing exactly on `row.start + len` is the NEXT row's first character in
|
|
195
|
+
// the layout (`cur === row end` is only kept when it is a wrap boundary),
|
|
196
|
+
// so a caret at the end of a SHORT last row must stay on its last character.
|
|
197
|
+
while (idx < row.start + rowChars.length) {
|
|
198
|
+
const cw = charWidth(rowChars[idx - row.start].codePointAt(0));
|
|
199
|
+
if (w + cw > want)
|
|
200
|
+
break;
|
|
201
|
+
w += cw;
|
|
186
202
|
idx++;
|
|
187
203
|
}
|
|
204
|
+
// Keep the caret INSIDE the target row: the layout moves a caret that sits
|
|
205
|
+
// on the row end onto the next row, which is exactly the "Up jumps two
|
|
206
|
+
// rows" bug.
|
|
207
|
+
if (idx > row.start + rowChars.length)
|
|
208
|
+
idx = row.start + rowChars.length;
|
|
209
|
+
if (idx === row.start + rowChars.length && rowChars.length > 0)
|
|
210
|
+
idx--;
|
|
188
211
|
return { ...s, cursor: idx };
|
|
189
212
|
}
|
|
190
213
|
/** Insert a newline; a trailing «\» before the cursor is removed first. */
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "zames_pro",
|
|
3
|
-
"version": "2.82.
|
|
3
|
+
"version": "2.82.68",
|
|
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": {
|