zames_pro 2.81.1 → 2.81.2

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 CHANGED
@@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [2.81.2] - 2026-10-21
11
+
12
+ ### Fixed
13
+
14
+ - **tools:** read-only mode drops concatenated/camelCase MCP writers
15
+
10
16
  ## [2.81.1] - 2026-10-21
11
17
 
12
18
  ### Added
package/dist/tools.js CHANGED
@@ -403,13 +403,34 @@ export function filterToolsByAllowList(tools, allowed) {
403
403
  // mutating VERBS in the tool name. It is a heuristic deny-list, not a proof:
404
404
  // an exotic server could name a mutating tool innocuously. The honest default
405
405
  // in read-only mode is therefore to drop everything that looks like a writer.
406
- const MCP_MUTATING_RE = /(^|_)(click|type|navigate|press|upload|select|drag|fill|hover|evaluate|run_code|run_|handle_dialog|key|screenshot|write|create|delete|update|set|put|post|patch|execute|exec|insert|remove|drop|restart|stop|start|install|kill|move|rename|copy|mkdir|rmdir|touch|chmod|chown)(_|$)/;
406
+ const MCP_MUTATING_WORDS = new Set(('click type navigate press upload select drag fill hover evaluate key ' +
407
+ 'screenshot write create delete update set put post patch execute exec ' +
408
+ 'insert remove drop restart stop start install kill move rename copy ' +
409
+ 'mkdir rmdir touch chmod chown').split(' '));
410
+ // Multi-word verbs are matched as a substring of the normalized name: they
411
+ // never stand alone as ONE `_word_`, so a word-set alone missed them.
412
+ const MCP_MUTATING_PHRASES = ['run_code', 'run_', 'handle_dialog'];
413
+ // A camelCase name is split BEFORE it is lowercased: `browserClick` used to
414
+ // become `browserclick` (one word, no verb) and slipped through read-only mode.
415
+ function splitCamelCase(s) {
416
+ return s.replace(/([a-z0-9])([A-Z])/g, '$1_$2');
417
+ }
407
418
  export function isMutatingMcpTool(name) {
408
419
  // Strip the server prefix and normalize separators to underscores so the
409
420
  // verb matcher sees "browser_click" -> "click".
410
421
  const tail = String(name).split('__').pop() || String(name);
411
- const norm = tail.toLowerCase().replace(/[^a-z0-9]+/g, '_');
412
- return MCP_MUTATING_RE.test('_' + norm + '_');
422
+ const norm = splitCamelCase(tail)
423
+ .toLowerCase()
424
+ .replace(/[^a-z0-9]+/g, '_');
425
+ if (MCP_MUTATING_PHRASES.some((p) => norm.includes(p)))
426
+ return true;
427
+ const words = norm.split('_').filter(Boolean);
428
+ if (words.some((w) => MCP_MUTATING_WORDS.has(w)))
429
+ return true;
430
+ // A CONCATENATED style (all lowercase, no separator: `browserclick`,
431
+ // `pageevaluate`) still hides a writer. A verb as a substring is safe here
432
+ // because every verb is a whole action word no read-only tool contains.
433
+ return [...MCP_MUTATING_WORDS].some((v) => norm.includes(v));
413
434
  }
414
435
  // Merge MCP tools into the base set. In read-only (plan) mode the MCP tools
415
436
  // must be filtered too: an MCP server (e.g. @playwright/mcp) exposes mutating
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zames_pro",
3
- "version": "2.81.1",
3
+ "version": "2.81.2",
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": {