zames_pro 2.82.140 → 2.82.141

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.
@@ -25,26 +25,31 @@ export const spinnerMessages = {
25
25
  },
26
26
  'editor.more': { ru: '…ещё {n}', en: '…{n} more' },
27
27
  'editor.page_hint': {
28
- ru: '(Ctrl+N/Ctrl+P — вверх/вниз, Tab — вставить)',
29
- en: '(Ctrl+N/Ctrl+P — up/down, Tab — insert)',
28
+ ru: '(Ctrl+N/Ctrl+P — выбор, Tab — вставить)',
29
+ en: '(Ctrl+N/Ctrl+P — select, Tab — insert)',
30
30
  },
31
31
  'editor.answer': { ru: '● Ответ', en: '● Answer' },
32
32
  // Shown in the full-screen log viewport before the first turn, so a fresh
33
33
  // chat is not a blank screen with no hint of what to do.
34
34
  'editor.empty_hint': {
35
- ru: 'Напишите задачу и нажмите Enter. /help — команды, Ctrl+J — новая строка.',
36
- en: 'Type a task and press Enter. /help for commands, Ctrl+J for a new line.',
35
+ ru: 'Напишите задачу и нажмите Enter. /help — команды, \\ + Enter — новая строка.',
36
+ en: 'Type a task and press Enter. /help for commands, \\ + Enter for a new line.',
37
37
  },
38
38
  // One-line key hint UNDER the input box (full-screen mode). Two variants:
39
39
  // with in-app wheel scroll the mouse belongs to the app, so selection needs
40
40
  // Shift; without it the terminal keeps the mouse and the wheel is inert.
41
+ // Kept SHORT: the row is truncated, and the long "up/down" / "top/bottom"
42
+ // tails pushed the MODE-specific part (wheel vs inert) off a narrow screen.
41
43
  'editor.keys_hint': {
42
- ru: 'выделение — Shift+клик · колесо — скролл · PgUp/PgDn — вверх/вниз · Home/End — в начало/конец',
43
- en: 'select — Shift+click · wheel — scroll · PgUp/PgDn — up/down · Home/End — top/bottom',
44
+ // The wheel belongs to the app ONLY in this mode; in SELECT mode the
45
+ // terminal keeps it (see useMouseWheel.ts), so that hint never advertises
46
+ // a wheel scroll.
47
+ ru: 'колесо — скролл · выделение — Shift+клик · Esc — стоп · PgUp/PgDn · Home/End',
48
+ en: 'wheel — scroll · select — Shift+click · Esc — stop · PgUp/PgDn · Home/End',
44
49
  },
45
50
  'editor.keys_hint_select': {
46
- ru: 'выделение — мышью · PgUp/PgDn — вверх/вниз · Home/End — в начало/конец',
47
- en: 'select — drag · PgUp/PgDn — up/down · Home/End — top/bottom',
51
+ ru: 'выделение — мышью · колесо инертно · Esc — стоп · PgUp/PgDn · Home/End',
52
+ en: 'select — drag · wheel inert · Esc — stop · PgUp/PgDn · Home/End',
48
53
  },
49
54
  // Reverse search (Ctrl+R) status line. The query may be empty.
50
55
  'editor.search_prompt': {
package/dist/index.js CHANGED
@@ -485,9 +485,9 @@ ${theme.bold(t('help.while_working'))}
485
485
  ${t('help.key.search')}
486
486
  ${t('help.key.words')}
487
487
  ${t('help.key.undo')}
488
+ ${t('help.key.clear_screen')}
488
489
  ${t('help.key.slash')}
489
490
  ${t('help.key.newline')}
490
- ${t('help.key.backslash')}
491
491
  ${t('help.key.attach')}
492
492
  ${t('help.key.esc')}
493
493
  ${t('help.key.bang')}
@@ -703,7 +703,7 @@ async function resolveWorkdir() {
703
703
  const dir = explicitDir ? path.resolve(explicitDir) : process.cwd();
704
704
  const stat = await fs.stat(dir).catch(() => null);
705
705
  if (!stat || !stat.isDirectory()) {
706
- throw new Error(t('msg.not_dir', { v: dir }));
706
+ throw new Error(t('cd.not_dir', { v: dir }));
707
707
  }
708
708
  return dir;
709
709
  }
@@ -1063,7 +1063,7 @@ async function main() {
1063
1063
  console.error(theme.warn(t('mcp.server_error', { name: srv.name, error: srv.error })));
1064
1064
  }
1065
1065
  for (const w of st.warnings)
1066
- console.error(theme.warn(w));
1066
+ console.error(theme.warn(t(w.key, w.params)));
1067
1067
  }
1068
1068
  catch (e) {
1069
1069
  console.error(theme.warn(t('mcp.load_failed', { v: e.message })));
@@ -1224,6 +1224,7 @@ async function main() {
1224
1224
  const recoverFromContextLimit = async () => {
1225
1225
  const res = await performCompact({
1226
1226
  browser,
1227
+ providerLabel: providerLabel(config.provider),
1227
1228
  currentChatId,
1228
1229
  workdir: currentWorkdir,
1229
1230
  locale: currentLocale,
@@ -2970,7 +2971,7 @@ async function main() {
2970
2971
  // finding it meant /chats (a network fetch) or copying the id.
2971
2972
  const last = loadLastSession(currentWorkdir, config.provider);
2972
2973
  if (!last || !last.id) {
2973
- console.error(theme.error(t('sessions.none')));
2974
+ console.error(theme.error(t('sessions.none_here')));
2974
2975
  continue;
2975
2976
  }
2976
2977
  if (editor)
@@ -3253,7 +3254,7 @@ async function main() {
3253
3254
  }
3254
3255
  }
3255
3256
  for (const w of st.warnings)
3256
- console.log(theme.warn(' ' + w));
3257
+ console.log(theme.warn(' ' + t(w.key, w.params)));
3257
3258
  continue;
3258
3259
  }
3259
3260
  if (lower === '/skills') {
@@ -3735,6 +3736,7 @@ async function main() {
3735
3736
  // paths stay identical (same retries, same fallback, same resend).
3736
3737
  const res = await performCompact({
3737
3738
  browser,
3739
+ providerLabel: providerLabel(config.provider),
3738
3740
  currentChatId,
3739
3741
  workdir: currentWorkdir,
3740
3742
  locale: currentLocale,
@@ -4198,6 +4200,7 @@ async function main() {
4198
4200
  ? async () => {
4199
4201
  const res = await performCompact({
4200
4202
  browser,
4203
+ providerLabel: providerLabel(config.provider),
4201
4204
  currentChatId,
4202
4205
  workdir: currentWorkdir,
4203
4206
  locale: currentLocale,
package/dist/mcp.js CHANGED
@@ -486,7 +486,10 @@ export async function createMcpPool(opts) {
486
486
  status: () => ({
487
487
  servers: infos,
488
488
  toolCount: tools.length,
489
- warnings: floating.map((n) => `MCP server "${n}" uses a floating version (@latest/@next); pin an exact version so the tool set does not change between runs.`),
489
+ warnings: floating.map((n) => ({
490
+ key: 'mcp.floating',
491
+ params: { v: n },
492
+ })),
490
493
  }),
491
494
  close: async () => {
492
495
  if (closed)
package/dist/prompt.js CHANGED
@@ -10,6 +10,17 @@
10
10
  // pasted text in the markers \x1b[200~ … \x1b[201~, so we know for sure
11
11
  // that this is a paste, not keyboard typing, and Enter inside it is not
12
12
  // treated as submission.
13
+ //
14
+ // A `data` chunk is a stream of UTF-8 BYTES and a terminal hands them over in
15
+ // whatever sizes the pty chose: an emoji (4 bytes) or any other non-ASCII
16
+ // character can be split between two reads. `Buffer#toString('utf-8')` decodes
17
+ // every read on its own, so a split character became a run of U+FFFD — the
18
+ // operator's answer (a login, a path, a Cyrillic task) arrived corrupted. The
19
+ // decoder below holds back an INCOMPLETE trailing sequence until the bytes
20
+ // that finish it arrive, and every read (keys, paste, the pasted tail) goes
21
+ // through it. The non-TTY path instead CONCATENATES the raw buffers and decodes
22
+ // once at EOF, so a split there heals by itself.
23
+ import { StringDecoder } from 'node:string_decoder';
13
24
  export async function promptOnce(question) {
14
25
  const stdin = process.stdin;
15
26
  const stdout = process.stdout;
@@ -71,8 +82,12 @@ export async function promptOnce(question) {
71
82
  line = line.slice(0, cursor) + clean + line.slice(cursor);
72
83
  cursor += clean.length;
73
84
  };
85
+ // One decoder for the WHOLE read loop: it keeps the bytes of a character
86
+ // that was split between two `data` events and prepends them to the next
87
+ // read, instead of turning both halves into U+FFFD.
88
+ const decoder = new StringDecoder('utf8');
74
89
  const onData = (buf) => {
75
- let s = buf.toString('utf-8');
90
+ let s = decoder.write(buf);
76
91
  // Fallback for terminals without bracketed paste: if the whole chunk is
77
92
  // a "bare" newline (one byte), then Enter was pressed → submit.
78
93
  // If newlines came TOGETHER with other text in one chunk — that's a
@@ -7,7 +7,7 @@ export function formatStatus(s, t = translate('en')) {
7
7
  const onoff = (b) => (b ? t('common.on') : t('common.off'));
8
8
  const lines = [];
9
9
  lines.push(t('status.workdir', { v: s.workdir }));
10
- lines.push(t('status.review_mode', { v: s.reviewMode || t('status.review_none') }));
10
+ lines.push(t('status.review_mode', { v: s.reviewMode || no }));
11
11
  if (s.reviewMode && s.origDir) {
12
12
  lines.push(t('status.orig_dir', { v: s.origDir }));
13
13
  }
@@ -36,7 +36,11 @@ export function formatStatus(s, t = translate('en')) {
36
36
  // A NEGATIVE tool count is nonsense (a broken MCP server status, a
37
37
  // hand-edited value): "MCP tools: -2" reads like a real measurement, the
38
38
  // same rule the token counter below already follows.
39
- const mcpCount = s.mcpToolCount === null || s.mcpToolCount < 0 ? none : s.mcpToolCount;
39
+ // `none` ("(none)") would claim that the tools themselves are absent;
40
+ // with no MCP pool configured the COUNT is simply unknown.
41
+ const mcpCount = s.mcpToolCount === null || s.mcpToolCount < 0
42
+ ? t('common.unknown')
43
+ : s.mcpToolCount;
40
44
  lines.push(t('status.mcp', { v: mcpCount }));
41
45
  // A NEGATIVE count is nonsense (a broken provider counter): show "unknown"
42
46
  // rather than a number that reads like a real measurement.
@@ -351,6 +351,11 @@ and the (MCP server: ...) note in its description tells you which server
351
351
  it belongs to. The JSON Schema in the description lists the exact fields
352
352
  (including their descriptions and enums) - follow it.
353
353
 
354
+ In plan (read-only) mode an MCP tool whose name looks mutating (click,
355
+ type, write, ...) is REMOVED from your tool set, exactly like the
356
+ built-in writers. The list you were given is the whole truth: if a tool
357
+ is not in it, it is not available in this run - do not try to call it.
358
+
354
359
  ## How to use tools
355
360
 
356
361
  To call ONE tool, respond with ONLY a JSON object (no markdown fences, no extra text):
@@ -420,6 +425,9 @@ reliably, pass the content in base64 instead of plain text:
420
425
 
421
426
  - Write: use 'content_base64' instead of 'content'.
422
427
  - Edit: use 'old_base64' / 'new_base64' instead of 'old_string' / 'new_string'.
428
+ - MultiEdit: use 'edits_base64' (base64 of the JSON array) instead of 'edits'.
429
+ - TodoWrite: use 'todos_base64' (base64 of the JSON array) instead of 'todos'.
430
+ - ApplyPatch: use 'patch_base64' instead of 'patch'.
423
431
 
424
432
  base64 alphabet is [A-Za-z0-9+/=] and is not corrupted. Encode with the
425
433
  base64 command or in Node via Buffer.from(text).toString('base64').
@@ -91,7 +91,7 @@ export function AskQuestion({ question, options, recommended, allowText, locale
91
91
  out.push(line);
92
92
  return out.length ? out : [''];
93
93
  };
94
- return (_jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: UI.accent, paddingX: 2, children: [_jsx(Text, { color: UI.title, bold: true, children: '◆ ' + t('askuser.title') }), wrap(question).map((line, i) => (_jsx(Text, { color: UI.text, children: line }, i))), _jsx(Text, { color: "#3a3f4b", children: '─'.repeat(innerCols) }), typing ? (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { color: UI.dim, children: t('askuser.your_answer') }), _jsxs(Text, { color: UI.accent, children: ['❯ ', text, '▏'] })] })) : (rows.map((label, i) => {
94
+ return (_jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: UI.accent, paddingX: 2, children: [_jsx(Text, { color: UI.title, bold: true, children: '◆ ' + t('askuser.title') }), wrap(question).map((line, i) => (_jsx(Text, { color: UI.text, children: line }, i))), _jsx(Text, { color: "#3a3f4b", children: '─'.repeat(innerCols) }), typing ? (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { color: UI.dim, children: t('askuser.your_answer') }), _jsx(Text, { color: UI.dim, children: t('askuser.enter_send') }), _jsxs(Text, { color: UI.accent, children: ['❯ ', text, '▏'] })] })) : (rows.map((label, i) => {
95
95
  const sel = i === cursor;
96
96
  const isRec = i === recommended;
97
97
  return (_jsxs(Text, { children: [_jsx(Text, { color: UI.accent, children: sel ? '❯ ' : ' ' }), _jsx(Text, { color: sel ? UI.accent : undefined, bold: sel, children: label }), isRec ? (_jsx(Text, { color: "#6fd0b0", children: ' (' + t('askuser.recommended') + ')' })) : null] }, i));
@@ -134,6 +134,13 @@ export class TuiEditor {
134
134
  // printAbove), so Ink must not patch them: an unmount (clearScreen)
135
135
  // would otherwise restore the native console and lose that routing.
136
136
  patchConsole: false,
137
+ // Shift+Enter is INDISTINGUISHABLE from a plain Enter unless the
138
+ // terminal disambiguates escape codes: both arrive as CR. The kitty
139
+ // keyboard protocol makes the modified form a distinct CSI-u
140
+ // sequence, which is what `dispatchKey` maps to a newline.
141
+ // 'auto' probes the terminal (CSI ? u) and stays silent when the
142
+ // terminal does not answer, so an unsupporting one is unaffected.
143
+ kittyKeyboard: { mode: 'auto' },
137
144
  alternateScreen: this.alternateScreen,
138
145
  });
139
146
  this.rendered = true;
@@ -45,8 +45,10 @@ export function HintBar({ hints, }) {
45
45
  *
46
46
  * The agent's answers are printed as pre-rendered ANSI (markdown.ts already
47
47
  * highlights with cli-highlight), so the live log does NOT use this component —
48
- * it exists for menus/panels that show a snippet inline (and for a future
49
- * structured log).
48
+ * it exists for menus/panels that show a snippet inline. No call site today:
49
+ * the Ctrl+Y / `/copy-code` feature that used it was removed, and plain `/copy`
50
+ * copies the whole answer, so `extractCodeBlocks` (src/code-blocks.ts) is only
51
+ * reached from its own tests.
50
52
  */
51
53
  export function CodeBlock({ code, lang, highlighted, width, hint, focused, }) {
52
54
  return (_jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: focused ? UI.accent : UI.border, paddingX: 1, width: width, children: [_jsxs(Box, { justifyContent: "space-between", children: [_jsx(Text, { color: UI.dim, children: lang || 'code' }), hint ? _jsx(Text, { color: UI.accent, children: hint }) : null] }), (highlighted || code).split(String.fromCharCode(10)).map((line, i) => (_jsx(Text, { children: line || ' ' }, i)))] }));
package/llms-full.txt CHANGED
@@ -1,7 +1,8 @@
1
1
  # zames_pro — full documentation for LLMs
2
2
 
3
3
  > Terminal coding agent that drives a real web chat LLM (DeepSeek, Qwen,
4
- > GLM) through a headless Playwright browser — no API key required.
4
+ > GLM) through a Playwright browser (DeepSeek and Qwen headless, GLM in a
5
+ > visible window) — no API key required.
5
6
  > Package: https://www.npmjs.com/package/zames_pro
6
7
  > Source: https://github.com/Viqto0r/zames_pro
7
8
 
@@ -111,7 +112,9 @@ Key pieces:
111
112
  - **Subagents** — the `Task` tool delegates a self-contained sub-task to an
112
113
  agent in its own separate chat (isolated context), which returns only a
113
114
  report, so heavy research does not flood the main context. On by default;
114
- tune with `browser.subagents` / `browser.maxSubagents`.
115
+ `browser.subagents` turns it off and `browser.maxSubagents` caps the runs
116
+ per TASK (default 3). Calls are sequential, not parallel, and the subtype
117
+ matters: `explore` is read-only, `general` may edit files.
115
118
  - **MCP support** — plug in external tool servers (e.g. `@playwright/mcp`).
116
119
  - **Scheduling** — `/loop`, `/cron` and `/jobs` repeat tasks on a timer.
117
120
  - **Bilingual UI** — Russian / English (`/config lang`).
@@ -271,8 +274,12 @@ The prompt is a small line editor with persistent history:
271
274
  - `Ctrl+_` — undo the last edit in the input line (a fat-fingered `Ctrl+U` /
272
275
  `Ctrl+K` is recoverable).
273
276
  - `Ctrl+U` — clear the line, `Ctrl+K` — delete to end of line, `Ctrl+W` —
274
- delete the word before the cursor, `Ctrl+←`/`Ctrl+→` — move by words.
275
- - `\` + `Enter`, `Ctrl+J`, `Ctrl+Enter` or `Shift+Enter` — insert a newline.
277
+ delete the word before the cursor, `Ctrl+←`/`Ctrl+→` — move by words,
278
+ `Ctrl+Delete`/`Alt+Delete` — delete the word after the cursor.
279
+ - `\` + `Enter` and `Ctrl+J` — insert a newline; these two work in
280
+ every terminal. `Ctrl+Enter` and `Shift+Enter` do it too, but only where the
281
+ terminal implements the kitty keyboard protocol: without it the terminal
282
+ sends a PLAIN Enter for Shift+Enter and the message is sent.
276
283
  - `/` + `Tab` — slash-command hints and completion.
277
284
  - `!command` — run a shell command directly, bypassing the model (like
278
285
  Claude Code's bash mode). The same sandbox guard as the `Bash` tool applies,
@@ -286,9 +293,10 @@ selected without leaving the terminal:
286
293
  wheel never scrolls the input history — history is arrow keys only.
287
294
  - `ui.mouseScroll=false` — the terminal owns the mouse again: normal text
288
295
  selection works and the wheel is inert.
289
- - `PgUp` / `PgDn` — move up/down the dialog half a screen.
290
- - `Home` / `End` — jump to the very top / bottom of the dialog (only while the
291
- input line is empty; with text typed they move the caret as usual).
296
+ - the mouse wheel, `PgUp` / `PgDn` (half a screen) and `Home` / `End` (the very
297
+ top / bottom) scroll the dialog; the wheel needs `ui.mouseScroll=true` (the default), and
298
+ Home/End jump only while the input line is empty (with text typed they
299
+ move the caret as usual).
292
300
  - To copy a LARGE block, use `/export` (writes the whole session as Markdown)
293
301
  or the transcript file (`/transcript` shows the path) — the terminal's own
294
302
  drag-select cannot reach past one screen.
@@ -297,8 +305,8 @@ Set `NO_COLOR=1` to disable colors (a calm default palette is used otherwise).
297
305
 
298
306
  ### Images and files
299
307
 
300
- You can paste an image or a file into the input line (Ctrl+Shift+V / Shift+Insert
301
- or the terminal's own paste). zames saves it under `<project>/tmp` and shows a
308
+ You can paste an image or a file into the input line (Shift+Insert or the
309
+ terminal's own paste; for a FILE from the clipboard press Ctrl+V). zames saves it under `<project>/tmp` and shows a
302
310
  marker in the line - `[image#1]` for images, `[file#1]` for other files - then
303
311
  uploads the real file to the chat together with your message. These are the
304
312
  same formats the DeepSeek / Qwen / GLM web chat accepts (PNG, JPEG, GIF, WEBP, BMP,
@@ -368,6 +376,8 @@ The agent has the same style of tools as Claude Code / Codex CLI:
368
376
  - **Git** — `GitStatus`, `GitDiff`, `GitLog`, `GitShow`, `GitBranchList`,
369
377
  `GitAdd`, `GitCommit`, `GitPush`.
370
378
  - **Web** — `WebFetch`, `WebSearch`.
379
+ - **Subagents** — `Task` (delegate a self-contained sub-task to an agent in
380
+ its own chat; `explore` is read-only, `general` may edit; capped per task).
371
381
  - **Operator** — `AskUser` (a modal question with options; skipped in plan
372
382
  mode so a plan is never interrupted).
373
383
  - **Service** — `respond` (final answer to the operator, ends the task).
@@ -415,8 +425,9 @@ commands (/new or /clear, /sessions, /chats, /resume-id, /last, /chat, /cd,
415
425
  - /review [focus] [--staged] — ask the agent to review uncommitted changes
416
426
  and report findings (no code changes).
417
427
  - /plan [on|off] — plan (read-only) mode. While it is on, the mutating tools
418
- (Write/Edit/MultiEdit/ApplyPatch/Bash, GitAdd/GitCommit/GitPush) are removed
419
- from the tool set, so the agent can investigate without touching the tree.
428
+ (Write/Edit/MultiEdit/ApplyPatch/Bash/BashOutput, GitAdd/GitCommit/GitPush,
429
+ AskUser) are removed from the tool set, and so are MCP tools with a mutating
430
+ name, so the agent can investigate without touching the tree.
420
431
  Start in it with `--plan`.
421
432
  - /compact — ask the active backend to compress the current chat into a handover
422
433
  summary, then open a NEW chat, resend the system prompt and post the summary
@@ -424,9 +435,10 @@ commands (/new or /clear, /sessions, /chats, /resume-id, /last, /chat, /cd,
424
435
  - /goal <condition> — set a **completion condition** (Claude Code parity). The
425
436
  agent starts working toward it at once and keeps starting new turns until a
426
437
  separate evaluator model judges the condition met. The goal clears itself
427
- automatically when it is met (or judged impossible), or with `/goal clear`.
428
- The condition is stored in `<project>/.zames-goal` (git-ignored) and restored
429
- on the next launch. `/goal` with no argument shows the current state.
438
+ automatically when it is met (or judged impossible), or with `/goal clear`
439
+ (or its synonym `/goal off`). The condition is stored in `<project>/.zames-goal`
440
+ (git-ignored) and restored on the next launch. `/goal` with no argument — or
441
+ `/goal on` — shows the current state.
430
442
  - /loop <interval> <task> — repeat a task periodically (e.g. `/loop 10m run the
431
443
  tests`). /cron "<min> <hour> <dom> <month> <dow>" <task> — run on a schedule.
432
444
  /jobs [rm <id>|clear] lists and stops them. A fired job is put into the same
@@ -440,8 +452,9 @@ tests`). /cron "<min> <hour> <dom> <month> <dow>" <task> — run on a schedule.
440
452
  "Web search" item in the "+" menu.
441
453
  These (and /queue, /jobs, /goal, `/config <sub>`) can be used WHILE the agent
442
454
  is working — they do not touch the in-flight generation.
443
- - /queue [clear] — list or clear the messages waiting to be sent after the
444
- current task.
455
+ - /queue [list|ls|clear|c|clean] — list (`list`/`ls`) or clear
456
+ (`clear`/`c`/`clean`) the messages waiting to be sent after the current
457
+ task.
445
458
 
446
459
  The token context is also shown live: the status line above the input has the
447
460
  spinner/text on the left and the context on the right (e.g. `125k · 13%`). The
@@ -547,8 +560,7 @@ too):
547
560
 
548
561
  - **Memory** (`@modelcontextprotocol/server-memory`) — a local knowledge graph
549
562
  (9 tools) for durable facts across chats. NOTE: zames already has `MEMORY.md`
550
-
551
- * `AGENTS.md`; add this only if you want a queryable graph.
563
+ + `AGENTS.md`; add this only if you want a queryable graph.
552
564
 
553
565
  Keep the stack SMALL: every server loads its tool definitions into the model's
554
566
  context. Add one when you feel its absence, not before.
@@ -564,13 +576,14 @@ You can view and change settings without leaving the agent — use the
564
576
  toggle in place; numbers and strings open an input prompt.
565
577
 
566
578
  ```
567
- /config interactive settings menu
568
- /config list print all editable settings
579
+ /config interactive settings menu (alias: menu)
580
+ /config list print all editable settings (aliases: show, ls)
569
581
  /config get <path> show a setting
570
582
  /config set <path> <value> change a setting
571
- /config reset <path> reset a setting to its default
572
- /config path show config file paths
583
+ /config reset <path> reset a setting to its default (alias: unset)
584
+ /config path show config file paths (alias: paths)
573
585
  /config lang <ru|en> switch interface and agent language
586
+ (aliases: language, язык)
574
587
  ```
575
588
 
576
589
  Examples:
package/llms.txt CHANGED
@@ -3,8 +3,8 @@
3
3
  > zames_pro (`zames_pro` on npm, binary `zames`) is a free, open-source
4
4
  > terminal coding agent that drives a real web chat LLM — DeepSeek
5
5
  > (chat.deepseek.com), Qwen (chat.qwen.ai) or GLM (chat.z.ai) — through a
6
- > headless Playwright browser, so it needs NO API key and bills nothing per
7
- > token. It behaves like Claude Code / Codex CLI in the terminal: reads and
6
+ > Playwright browser (DeepSeek and Qwen headless, GLM in a visible window), so
7
+ > it needs NO API key and bills nothing per token. It behaves like Claude Code / Codex CLI in the terminal: reads and
8
8
  > edits files, runs shell commands, greps the repo, and commits to git.
9
9
 
10
10
  This file follows the llms.txt convention (https://llmstxt.org): a short,
@@ -20,6 +20,8 @@ LLM-friendly map of the project. Everything below is plain Markdown.
20
20
  - **Supported backends:** DeepSeek (`chat.deepseek.com`, default), Qwen
21
21
  (`chat.qwen.ai`), GLM (`chat.z.ai`). Live switch with
22
22
  `/provider <deepseek|qwen|glm>`; each backend keeps its own browser profile.
23
+ DeepSeek and Qwen run headless; GLM runs with a VISIBLE window by default,
24
+ because z.ai answers every headless send with a slider captcha.
23
25
  - **Language / stack:** TypeScript (strict), Node.js >= 22, Playwright,
24
26
  Ink/React TUI, MCP client.
25
27
  - **License:** MIT. **Not affiliated** with DeepSeek, Alibaba or Zhipu AI.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "zames_pro",
3
- "version": "2.82.140",
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.",
3
+ "version": "2.82.141",
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": {
7
7
  "zames": "dist/index.js"
@@ -27,6 +27,13 @@ Shrink the failure to the smallest unit that still fails.
27
27
  remember writing.
28
28
  - Check the obvious causes FIRST: wrong file, stale build, cached state,
29
29
  different config, an earlier error swallowed by a catch.
30
+ - In zames the evidence is already on disk: the transcript at
31
+ `~/.zames/logs/*.jsonl` (`/transcript` prints the exact path of THIS run),
32
+ the raw answer bodies under `~/.zames/net-log` when started with
33
+ `ZAMES_NET_DEBUG=1` (`npm run dev` sets it), and the per-send telemetry at
34
+ `~/.zames/logs/sends-<provider>.jsonl` (written in dev mode and when
35
+ `browser.sendTelemetry` is on). Read them BEFORE guessing — most "it hangs
36
+ / it stopped" reports are visible there.
30
37
 
31
38
  ## Phase 3 — Hypothesize (one at a time)
32
39
 
@@ -32,3 +32,8 @@ RED → GREEN → REFACTOR. The order is the point, not a formality.
32
32
  CODE was wrong; do not just move the assertion.
33
33
  - If the code was written before its test, delete and rewrite it driven by
34
34
  the test — otherwise the test is shaped around the implementation.
35
+ - A test that writes a temp dir or file cleans it up itself: in this repo
36
+ always go through `test/tmp-dir.ts` (`makeTmpDir(t, prefix)` /
37
+ `makeTmpDirSync`), which registers the `t.after` cleanup. On WSL a leaked
38
+ `os.tmpdir()` entry lives inside ext4.vhdx and never returns its space to
39
+ the Windows host, so an abandoned temp dir fragments the disk permanently.
@@ -24,6 +24,11 @@ from the real artifact — not from your intent.
24
24
  5. **State the evidence** in the final report — the exact command and its
25
25
  result — so the operator can reproduce it. "Tests pass" without the
26
26
  command is not evidence.
27
+ 6. **In zames the report is ONE `respond` call.** A long task may have
28
+ produced several findings along the way; the operator only ever reads the
29
+ LAST `respond` before the run stops, so put the complete evidence there —
30
+ never split it across intermediate messages, and never end a turn on a
31
+ bare text update with work still pending.
27
32
 
28
33
  ## The two failure modes this prevents
29
34
 
@@ -38,3 +38,15 @@ Because there is no separate plan file unless the operator asks for one, the
38
38
  plan lives in your reasoning and, for a long task, in a TodoWrite list — one
39
39
  entry per step, status updated as you go. Do not narrate the plan to the
40
40
  operator between tool calls; the todo list IS the visible plan.
41
+
42
+ Two more constraints follow from the same design:
43
+
44
+ - **A plan is not a report.** The operator sees ONLY the last `respond`
45
+ before the run stops, so the plan and the per-step evidence must not be
46
+ split across intermediate messages — put the final evidence in that one
47
+ `respond`.
48
+ - **Subagents do not parallelise the plan.** A `Task` call runs in a FRESH
49
+ isolated chat and returns only a report; zames has ONE browser and ONE send
50
+ slot, so subagents are SEQUENTIAL. Use them to keep a broad read-only
51
+ investigation out of the main context — never to "go faster", and never for
52
+ a step that must be applied in order with the main chat.