zames_pro 2.7.0 → 2.9.0

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.
@@ -13,6 +13,71 @@ function readAttr(attrs, name) {
13
13
  const m = attrs.match(re);
14
14
  return m ? m[2] : null;
15
15
  }
16
+ // The model sometimes produces a "hybrid" call: the tool name is an attribute
17
+ // AND the arguments are inline JSON in the SAME opening tag, without any
18
+ // <parameter> children. A real case from the transcript:
19
+ // <|DSML|invoke name="GitAdd", "args" {"paths": "AGENTS.md src/index.ts"}>
20
+ // The standard <parameter> parser misses it, and the call is silently lost
21
+ // (the agent then stalls). Here we look for the first JSON object inside the
22
+ // attributes/body and parse it as args.
23
+ function parseInlineJsonArgs(s) {
24
+ const Q = String.fromCharCode(34);
25
+ // Find a plausible start of a JSON object: `{` or `"args" {`/`'args' {`.
26
+ const startRe = /\{|["']args["']\s*[:=]?\s*\{/i;
27
+ const m = startRe.exec(s);
28
+ if (!m)
29
+ return null;
30
+ const from = m.index;
31
+ // Scan for a balanced {...} block (string-aware) and try to parse it.
32
+ let depth = 0;
33
+ let inStr = false;
34
+ let esc = false;
35
+ let end = -1;
36
+ for (let i = from; i < s.length; i++) {
37
+ const c = s[i];
38
+ if (esc) {
39
+ esc = false;
40
+ continue;
41
+ }
42
+ if (c === '\\') {
43
+ esc = true;
44
+ continue;
45
+ }
46
+ if (c === Q) {
47
+ inStr = !inStr;
48
+ continue;
49
+ }
50
+ if (inStr)
51
+ continue;
52
+ if (c === '{')
53
+ depth++;
54
+ else if (c === '}') {
55
+ depth--;
56
+ if (depth === 0) {
57
+ end = i + 1;
58
+ break;
59
+ }
60
+ }
61
+ }
62
+ if (end === -1)
63
+ return null;
64
+ let frag = s.slice(from, end).trim();
65
+ // Drop a leading `"args" {` / `'args' {` / `args = {` prefix so only the
66
+ // object itself is left.
67
+ const lead = /^["']?args["']?\s*[:=]?\s*/.exec(frag);
68
+ if (lead)
69
+ frag = frag.slice(lead[0].length);
70
+ for (const candidate of [frag, frag.replace(/'/g, Q)]) {
71
+ try {
72
+ const parsed = JSON.parse(candidate);
73
+ if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) {
74
+ return parsed;
75
+ }
76
+ }
77
+ catch { }
78
+ }
79
+ return null;
80
+ }
16
81
  // Extracts parameters from an <invoke> body. The opening and closing tags may
17
82
  // carry an arbitrary prefix (DSML, etc.), and some models confuse tag pairs
18
83
  // (<parameter …> … </|DSML| parameter>). The regex below matches any pair
@@ -57,6 +122,16 @@ export function parseXmlToolCalls(text) {
57
122
  const closeMatch = closeRe.exec(rest);
58
123
  const body = closeMatch ? rest.slice(0, closeMatch.index) : rest;
59
124
  const args = parseParameters(body);
125
+ // Hybrid form: the arguments are inline JSON in the SAME invoke tag
126
+ // (e.g. `<|DSML|invoke name="GitAdd", "args" {"paths": "..."}>`), with no
127
+ // <parameter> children. Fall back to the raw invoke head + body.
128
+ if (Object.keys(args).length === 0) {
129
+ const inline = parseInlineJsonArgs(m[0] + body);
130
+ if (inline) {
131
+ calls.push({ tool: name, args: inline });
132
+ continue;
133
+ }
134
+ }
60
135
  // Some models put the whole JSON arguments object into a single
61
136
  // parameter named args. We unwrap it so there's no
62
137
  // {args: {args: {...}}}.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zames_pro",
3
- "version": "2.7.0",
3
+ "version": "2.9.0",
4
4
  "description": "Terminal coding agent over chat.deepseek.com via Playwright",
5
5
  "type": "module",
6
6
  "bin": {
@@ -1,67 +1,94 @@
1
- // Automatically install the Chromium build and system dependencies
2
- // that Playwright needs.
3
- //
4
- // Runs when the zames package is installed so the user does not have to run
5
- // "npx playwright install chromium" / "install-deps chromium" by hand.
6
- //
7
- // On Linux (including WSL) the browser binary also needs system libraries.
8
- // They are installed via "install-deps", which requires root (sudo).
9
- // If we are not root and sudo is not passwordless, we skip it and tell the
10
- // user the exact command to run.
11
- //
12
- // Install failure is NOT fatal: without network access (or in CI) the
13
- // package install must still succeed.
14
-
15
1
  import { spawnSync } from 'node:child_process'
16
2
 
3
+ const NL = String.fromCharCode(10)
17
4
  const isWin = process.platform === 'win32'
5
+ const isMac = process.platform === 'darwin'
6
+ const isLinux = process.platform === 'linux'
7
+
8
+ function run(cmd, args, opts) {
9
+ return spawnSync(cmd, args, Object.assign({ stdio: 'inherit', shell: isWin }, opts || {}))
10
+ }
18
11
 
19
- // npm puts node_modules/.bin on PATH for lifecycle scripts, so the local
20
- // playwright CLI is resolvable. On Windows npm runs scripts through cmd.exe,
21
- // so shell: true is needed for the .cmd shim to be found.
22
- function run(cmd, args) {
23
- return spawnSync(cmd, args, {
24
- stdio: 'inherit',
25
- shell: isWin,
26
- })
12
+ function has(cmd) {
13
+ if (isWin) {
14
+ const r = spawnSync('where', [cmd], { stdio: 'ignore' })
15
+ return !r.error && r.status === 0
16
+ }
17
+ const r = spawnSync('sh', ['-c', 'command -v "$1"', 'sh', cmd], { stdio: 'ignore' })
18
+ return !r.error && r.status === 0
19
+ }
20
+
21
+ function isRoot() {
22
+ return typeof process.getuid === 'function' && process.getuid() === 0
27
23
  }
28
24
 
29
25
  function canSudo() {
30
- // Already root? No sudo needed.
31
- if (typeof process.getuid === 'function' && process.getuid() === 0) return true
32
- // Passwordless sudo (common in WSL / CI images).
33
- const r = run('sudo', ['-n', 'true'])
34
- return !r.error && r.status === 0
26
+ if (isRoot()) return true
27
+ const r = spawnSync('sudo', ['-n', 'true'], { stdio: 'ignore' })
28
+ return !r.error && r.status === 0
29
+ }
30
+
31
+ const MANAGERS = [
32
+ { bin: 'apt-get', args: (p) => ['install', '-y', p], update: ['update'] },
33
+ { bin: 'dnf', args: (p) => ['install', '-y', p] },
34
+ { bin: 'yum', args: (p) => ['install', '-y', p] },
35
+ { bin: 'pacman', args: (p) => ['-S', '--noconfirm', p] },
36
+ { bin: 'zypper', args: (p) => ['install', '-y', p] },
37
+ { bin: 'apk', args: (p) => ['add', p] },
38
+ ]
39
+
40
+ function asRoot(cmd, args) {
41
+ if (isRoot()) return run(cmd, args)
42
+ return run('sudo', [cmd].concat(args))
43
+ }
44
+
45
+ function installPackages(pkgs) {
46
+ const mgr = MANAGERS.find((m) => has(m.bin))
47
+ if (!mgr) return false
48
+ if (mgr.update) asRoot(mgr.bin, mgr.update)
49
+ let any = false
50
+ for (const p of pkgs) {
51
+ const r = asRoot(mgr.bin, mgr.args(p))
52
+ if (!r.error && r.status === 0) any = true
53
+ }
54
+ return any
35
55
  }
36
56
 
37
- // 1) Browser binary for this Playwright version.
38
57
  const browser = run('playwright', ['install', 'chromium'])
39
58
  if (browser.error || browser.status !== 0) {
40
- console.warn(
41
- '\nzames: could not install Chromium for Playwright automatically.\n' +
42
- ' Run it manually: npx playwright install chromium\n',
43
- )
44
- process.exit(0)
59
+ console.warn(NL + 'zames: could not install Chromium for Playwright automatically.' + NL +
60
+ ' Run it manually: npx playwright install chromium' + NL)
61
+ process.exit(0)
62
+ }
63
+
64
+ if (isLinux) {
65
+ if (canSudo()) {
66
+ const deps = run('playwright', ['install-deps', 'chromium'])
67
+ if (deps.error || deps.status !== 0) {
68
+ console.warn(NL + 'zames: could not install Chromium system dependencies automatically.' + NL +
69
+ ' Run it manually: sudo npx playwright install-deps chromium' + NL)
70
+ }
71
+ } else {
72
+ console.warn(NL + 'zames: on Linux/WSL Chromium needs system libraries (sudo required).' + NL +
73
+ ' Run it once manually: sudo npx playwright install-deps chromium' + NL)
74
+ }
45
75
  }
46
76
 
47
- // 2) System libraries (Linux / WSL only). Without them Chromium fails
48
- // to launch with "error while loading shared libraries".
49
- if (!isWin) {
50
- if (canSudo()) {
51
- const deps = run('playwright', ['install-deps', 'chromium'])
52
- if (deps.error || deps.status !== 0) {
53
- console.warn(
54
- '\nzames: could not install Chromium system dependencies automatically.\n' +
55
- ' Run it manually: sudo npx playwright install-deps chromium\n',
56
- )
57
- }
58
- } else {
59
- console.warn(
60
- '\nzames: on Linux/WSL Chromium needs system libraries (sudo required).\n' +
61
- ' Run it once manually: sudo npx playwright install-deps chromium\n',
62
- )
63
- }
77
+ if (isLinux) {
78
+ const haveXclip = has('xclip') || has('xsel')
79
+ const haveWayland = has('wl-paste')
80
+ if (!haveXclip || !haveWayland) {
81
+ if (!canSudo()) {
82
+ console.warn(NL + 'zames: pasting images from the clipboard needs a clipboard tool.' + NL +
83
+ ' Install one (root required), e.g.:' + NL +
84
+ ' sudo apt install xclip # X11 (Debian/Ubuntu)' + NL +
85
+ ' sudo apt install wl-clipboard # Wayland' + NL +
86
+ ' Without it, paste a file path or use the attach button in the browser.' + NL)
87
+ } else if (!installPackages(['xclip', 'wl-clipboard'])) {
88
+ console.warn(NL + 'zames: could not install a clipboard tool automatically.' + NL +
89
+ ' Install xclip (X11) or wl-clipboard (Wayland) manually.' + NL)
90
+ }
91
+ }
64
92
  }
65
93
 
66
- // Never fail the package install because of a browser download.
67
94
  process.exit(0)