zames_pro 2.66.0 → 2.67.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.
package/CHANGELOG.md CHANGED
@@ -7,6 +7,92 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [2.67.0] - 2026-10-08
11
+
12
+ ### Added
13
+
14
+ - **agent:** one-shot exit code, recursive self-review, MCP dedupe/truncate/plan-filter, transcript flush (N3/N4/N5/N9/N20/N21)
15
+
16
+ ### Fixed
17
+
18
+ - **input:** CSI-u Delete, visual-row Up/Down, ESC disambiguation, Ctrl+L/PageUp (N27/N28/N29/N30)
19
+ - **security:** close shell-injection, symlink-escape and SSRF-redirect holes (N1/N2/N6/N7/N17/N18/N19/N22/N23)
20
+
21
+ ### Fixed
22
+
23
+ - **tools:** Edit/MultiEdit no longer corrupt dollar patterns (`$&`, `$$`, `$1`)
24
+ in `new_string` — the replacement now uses the functional form instead of a
25
+ string replacer.
26
+ - **tools:** Grep and findstr are run through `execFile` with an argument
27
+ array instead of a shell string, so a `$(...)` pattern is no longer executed
28
+ as a command.
29
+ - **git:** GitShow/GitDiff/GitAdd/GitPush/GitCommit now use `execFile`; `ref`
30
+ and `path` are validated (a leading `-` is rejected) — command/option
31
+ injection through the arguments of read-only tools is closed.
32
+ - **sandbox:** file tools resolve the real path (`fs.realpath`) and reject a
33
+ symlink pointing outside the working directory.
34
+ - **shell:** `assertCommandInsideRoot` expands `~`/`$HOME`, sees a `cd` inside
35
+ a subshell/backticks and rejects `eval` with `cd`.
36
+ - **plan mode:** MCP tools are now filtered for read-only too (mutating verbs
37
+ are dropped).
38
+ - **self-review:** the snapshot and diff/apply walk src/ subdirectories
39
+ recursively (`i18n/`, `input/`) — they used to be silently missing from the
40
+ snapshot.
41
+ - **one-shot `--task`:** on an agent error / iteration limit / watchdog the
42
+ process now exits with code 1 instead of 0.
43
+ - **input:** Ctrl+Delete and Delete now work under the CSI-u (kitty) protocol:
44
+ `CSI 3;5u`/`3;3u`/`3u`.
45
+ - **input:** Up/Down move the cursor across VISUAL rows of a wrapped line, not
46
+ only across logical lines.
47
+ - **input:** a lone ESC no longer aborts the generation when a control
48
+ sequence arrives in two chunks — a short timeout disambiguation.
49
+ - **input:** Ctrl+L clears the screen and PageUp/PageDown page the suggestion
50
+ list; an unknown control sequence is logged in debug instead of being
51
+ swallowed silently.
52
+ - **MCP:** duplicate tool names are disambiguated with a numeric suffix so the
53
+ second tool is not silently unreachable.
54
+ - **MCP:** a tool result is truncated with an explicit marker — a single call
55
+ (browser_snapshot and the like) no longer floods the context.
56
+ - **transcript:** `close()` waits for the flush (it returns a promise) so the
57
+ final events reach the file on the exit paths.
58
+ - **web:** `WebFetch` re-validates every redirect hop against the SSRF guard
59
+ and checks the final URL of a headless render.
60
+ - **permissions:** a `path` rule now also matches the file headers of an
61
+ `ApplyPatch` and path-looking arguments of MCP tools.
62
+ - **scheduler:** `nextCronTime` parses the cron expression once instead of on
63
+ every scanned minute.
64
+ - **git:** `formatGitContext` picks a code fence longer than any backtick run
65
+ in the preview, so a filename with backticks cannot break the markdown.
66
+ - **fsutil:** secrets and state are written with 0600 permissions;
67
+ `writeFileAtomic` fsyncs the file before rename (and the directory after)
68
+ for durability on a power loss.
69
+
70
+ ### Changed
71
+
72
+ - **docs:** SECURITY.md updated for the permissions policy, the symlink guard
73
+ and the plan-mode MCP caveat; DEVELOPING.md module sizes refreshed.
74
+ - **cleanup:** removed the dead exports `listConfiguredServers`,
75
+ `builtinSkills` and `findFileByName`.
76
+ - **tests:** the MCP result cap, `htmlToText` and the DuckDuckGo parser are
77
+ now covered, and `web.ts`/`spinner.ts` gained coverage floors.
78
+
79
+ ### Security
80
+
81
+ - Shared `shellQuote` helper for arguments passed to the shell (single quotes
82
+ with internal quotes doubled).
83
+
84
+ ## [2.66.1] - 2026-10-07
85
+
86
+ ### Changed
87
+
88
+ - README: the Russian translation is now folded into `<details>` directly in
89
+ `README.md`, so it can be read on the npm page without leaving GitHub. npm
90
+ renders the readme with the same GitHub Flavored Markdown as GitHub, and a
91
+ separate `README.ru.md` is not visible on the npm page (npm has one readme
92
+ per package). Both language versions are assembled from
93
+ `docs/readme.{en,ru}.md` by `npm run build:readme`;
94
+ `test/readme-built.test.ts` guards against drift.
95
+
10
96
  ## [2.66.0] - 2026-10-07
11
97
 
12
98
  ### Added
@@ -25,151 +111,148 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
25
111
 
26
112
  ### Fixed
27
113
 
28
- - Длинные строки preview больше не создают горизонтальный скролл в
29
- терминале: `toolCall`/`toolResult` (LineEditor и спиннер) теперь режут
30
- превью по ВИДИМОЙ ШИРИНЕ терминала (`truncateToWidth`), а не по числу
31
- символов. Раньше длинная команда/результат печатались шире экрана.
32
- - Ctrl+Delete / Ctrl+Backspace (и Alt+Delete / Alt+Backspace) теперь удаляют
33
- слово в строке ввода. Раньше эти escape-последовательности попадали в
34
- общий пропуск клавиш и ничего не делали. Поддержаны варианты: `ESC[3;5~`
35
- (xterm Ctrl+Delete), `ESC[3;3~` (Alt+Delete), `ESC DEL`/`ESC 8`
36
- (Alt/Ctrl+Backspace) и kitty-протокол `ESC[127;5u` / `ESC[127;3u`.
37
- Новый метод `_deleteWordRight()` + тест `test/editor-word-delete.test.ts`.
38
- - Меню `/config` теперь держит ВЫБРАННЫЙ пункт на экране: окно строится
39
- «назад» от курсора с учётом строк, которые занимают заголовки групп
40
- (раньше индексный `scrollTop` мог вытолкнуть выбранную строку вниз за
41
- пределы окна).
42
- - `/new` сбрасывает счётчик контекста: `_lastTokenUsage` копится НА ЧАТ,
43
- и без сброса в пустом чате оставался старый `ctx: 302k · 30%` до первой
44
- отправки. Тест в `test/newchat-verify.test.ts`.
114
+ - Long preview lines no longer create a horizontal scrollbar in the terminal:
115
+ `toolCall`/`toolResult` (LineEditor and spinner) now clip the preview by the
116
+ VISIBLE terminal width (`truncateToWidth`) instead of by character count. A
117
+ long command/result used to print wider than the screen.
118
+ - Ctrl+Delete / Ctrl+Backspace (and Alt+Delete / Alt+Backspace) now delete a
119
+ word in the input line. These escape sequences used to fall through the
120
+ generic key skip and did nothing. Supported variants: `ESC[3;5~` (xterm
121
+ Ctrl+Delete), `ESC[3;3~` (Alt+Delete), `ESC DEL`/`ESC 8`
122
+ (Alt/Ctrl+Backspace) and the kitty protocol `ESC[127;5u` / `ESC[127;3u`.
123
+ New `_deleteWordRight()` method + `test/editor-word-delete.test.ts`.
124
+ - The `/config` menu now keeps the SELECTED item on screen: the window is
125
+ built "backwards" from the cursor, taking into account the rows the group
126
+ headings occupy (previously an index-based `scrollTop` could push the
127
+ selected row below the window).
128
+ - `/new` resets the context counter: `_lastTokenUsage` accumulates PER CHAT,
129
+ and without a reset an empty chat kept showing the old `ctx: 302k · 30%`
130
+ until the first send. Test in `test/newchat-verify.test.ts`.
45
131
 
46
132
  ## [2.65.0] - 2026-10-07
47
133
 
48
134
  ### Changed
49
135
 
50
- - README-скриншот `docs/demo.png` перегенерирован на английском языке
51
- (раньше был на русском). Воспроизводимый генератор
52
- `npm run render-demo` (`scripts/render-demo.mjs`) рендерит реальную
53
- раскладку редактора и палитру темы через headless Chromium с
54
- изолированным профилем.
55
- - README: ASCII-схема «как это работает» заменена на диаграмму Mermaid
56
- (стрелки не «плывут») плюс текстовое описание словами.
57
- - Убраны неиспользуемые файлы: `logo.jpg` (в README используется только
58
- `logo-small.jpg`) и заготовка `docs/demo.tape` (VHS-рендер так и не был
59
- сгенерирован). `logo.jpg` удалён и из списка `files` в package.json.
136
+ - The README screenshot `docs/demo.png` was regenerated in English (it used to
137
+ be in Russian). The reproducible generator `npm run render-demo`
138
+ (`scripts/render-demo.mjs`) renders the real editor layout and theme palette
139
+ through headless Chromium with an isolated profile.
140
+ - README: the ASCII "how it works" diagram was replaced by a Mermaid diagram
141
+ (the arrows no longer "float") plus a textual description in words.
142
+ - Removed unused files: `logo.jpg` (only `logo-small.jpg` is used in the
143
+ README) and the `docs/demo.tape` draft (the VHS render was never generated).
144
+ `logo.jpg` was also removed from the `files` list in package.json.
60
145
 
61
146
  ### Fixed
62
147
 
63
- - Перерисовка терминала после ресайза окна: относительный стирающий
64
- `ESC[n A` после изменения размера попадал на устаревшую строку (терминал
65
- переформатировал переносы), из-за чего статус/инпут рисовались не там.
66
- Теперь после ресайза блок заново «прибивается» к низу (home + padding),
67
- история скроллбэка сохраняется. Тест в `test/terminal-drift.test.ts`.
68
- - Живая смена языка (`/config lang`) не доходила до двух «одноразово
69
- созданных» объектов: спиннер думающих фраз брал язык по умолчанию
70
- (`randomThinkingPhrase()` вместо `randomThinkingPhrase(this.locale)`),
71
- а `DeepSeekBrowser` печатал свои уведомления (`ds.*`) на языке,
72
- зафиксированном при старте. Из-за этого при английском UI всплывали
73
- русские «Структурирую мысли…» и «⏳ DeepSeek оборвал ответ…». Добавлен
74
- `DeepSeekBrowser.setLocale()`, вызываемый из `setConfigRuntime`.
75
- - Меню `/config` теперь рисуется ОКНОМ по высоте терминала (раньше весь
76
- список из 49 полей выводился одним блоком). На невысоком терминале блок
77
- уходил верхними строками за экран, из-за чего восстановление курсора
78
- `ESC[lastRows A` попадало не на ту строку и навигация стрелками «не
79
- скроллила» список. Заодно исправлена мёртвая регулярка снятия ANSI
80
- (лишний обратный апостроф) в `src/config-menu.ts`.
148
+ - Terminal repaint after a window resize: the relative erase `ESC[n A` after a
149
+ size change landed on a stale row (the terminal re-flowed the wraps), so the
150
+ status/input were drawn in the wrong place. After a resize the block is
151
+ re-pinned to the bottom (home + padding), and the scrollback history is kept.
152
+ Test in `test/terminal-drift.test.ts`.
153
+ - A live language change (`/config lang`) did not reach two "created once"
154
+ objects: the thinking-phrase spinner took the default language
155
+ (`randomThinkingPhrase()` instead of `randomThinkingPhrase(this.locale)`),
156
+ and `DeepSeekBrowser` printed its notices (`ds.*`) in the language fixed at
157
+ startup. So with an English UI Russian thinking/notice phrases surfaced.
158
+ Added `DeepSeekBrowser.setLocale()`, called from `setConfigRuntime`.
159
+ - The `/config` menu is now drawn as a WINDOW sized to the terminal height
160
+ (previously the whole list of 49 fields was printed as one block). On a short
161
+ terminal the block scrolled off the top, so restoring the cursor with
162
+ `ESC[lastRows A` landed on the wrong row and arrow navigation "did not
163
+ scroll" the list. Also fixed a dead ANSI-strip regex (a stray backtick) in
164
+ `src/config-menu.ts`.
81
165
 
82
166
  ## [2.64.1] - 2026-10-07
83
167
 
84
168
  ### Changed
85
169
 
86
- - README: добавлен скриншот терминальной сессии (`docs/demo.png`) под
87
- шапкой, чтобы интерфейс был виден сразу; скрипт воспроизводимого
88
- VHS-демо (`docs/demo.tape`) для будущего GIF.
170
+ - README: added a terminal session screenshot (`docs/demo.png`) under the
171
+ header so the interface is visible immediately; a reproducible VHS demo
172
+ script (`docs/demo.tape`) for a future GIF.
89
173
 
90
174
  ## [2.64.0] - 2026-10-06
91
175
 
92
176
  ### Added
93
177
 
94
- - Генератор черновика CHANGELOG из conventional-commits (BACKLOG D2):
95
- `npm run changelog:draft [ref]` печатает готовый блок для «Unreleased» из
96
- коммитов после последнего тега (или указанного ref). Чистый модуль
178
+ - A CHANGELOG draft generator from conventional commits (BACKLOG D2):
179
+ `npm run changelog:draft [ref]` prints a ready "Unreleased" block from the
180
+ commits after the last tag (or the given ref). Pure module
97
181
  `src/changelog.ts` (`parseConventionalCommit` / `groupCommits` /
98
- `renderChangelogDraft`, покрыт тестами). Файл `CHANGELOG.md` НЕ
99
- перезаписывается автоматически — черновик ревьюится вручную.
182
+ `renderChangelogDraft`, unit-tested). The `CHANGELOG.md` file is NOT
183
+ overwritten automatically — the draft is reviewed by hand.
100
184
 
101
185
  ### Changed
102
186
 
103
- - Рефакторинг (BACKLOG C3, шаг 1): разрешение путей вложения и инлайн
104
- `@file`-ссылок вынесены из `src/index.ts` в `src/attach-refs.ts`
105
- (`resolveAttachPath` / `inlineAtRefs`) — теперь это отдельный тестируемый
106
- модуль.
187
+ - Refactor (BACKLOG C3, step 1): attachment path resolution and `@file`
188
+ reference inlining were moved out of `src/index.ts` into
189
+ `src/attach-refs.ts` (`resolveAttachPath` / `inlineAtRefs`) — now a separate
190
+ testable module.
107
191
 
108
192
  ## [2.63.1] - 2026-10-06
109
193
 
110
194
  ### Fixed
111
195
 
112
- - Мигание таймера в статусе паузы перед отправкой: `sendPause()` (и
113
- `LineEditor`, и non-TTY `SpinnerUI`) перерисовывал статус БЕЗ хвоста
114
- «elapsed»/бейджа задач, а тик анимации рисовал его С ним — раз в секунду
115
- подпись `· 1m 50s` исчезала и появлялась. Теперь обновление собирает тот же
116
- хвост, что и тик. Регрессионный тест в test/compact-statusline.test.ts.
196
+ - Timer flicker in the pre-send pause status: `sendPause()` (both `LineEditor`
197
+ and the non-TTY `SpinnerUI`) repainted the status WITHOUT the
198
+ "elapsed"/task-badge tail, while the animation tick drew it WITH it — once a
199
+ second the `· 1m 50s` label disappeared and reappeared. The update now builds
200
+ the same tail as the tick. Regression test in test/compact-statusline.test.ts.
117
201
 
118
202
  ### Changed
119
203
 
120
- - README: центрированная шапка, логотип крупнее (640px-ассет, 430px показ),
121
- диаграмма «How it works», оглавление и секция Links.
122
- - Dependabot: мажорные обновления игнорируются (`semver-major`), расписание
123
- раз в месяц, авто-мерж только для patch/minor и только для PR бота
124
- (проверка автора и ветки); workflow авто-мержа. Ветка `master` защищена
125
- ruleset: PR обязателен, required-check — стабильный job `ci`.
204
+ - README: centered header, larger logo (640px asset, 430px display), a "How
205
+ it works" diagram, a table of contents and a Links section.
206
+ - Dependabot: major updates are ignored (`semver-major`), monthly schedule,
207
+ auto-merge only for patch/minor and only for bot PRs (author and branch
208
+ checks); auto-merge workflow. The `master` branch is protected by a ruleset:
209
+ PR required, required check is the stable `ci` job.
126
210
 
127
211
  ## [2.63.0] - 2026-10-06
128
212
 
129
213
  ### Added
130
214
 
131
- - Реальные подтверждения действий (BACKLOG C1): политика approval в
132
- `.zames/permissions.json` (`default` + `rules` с regexp по `tool`/`command`/
133
- `path` и действием `allow`|`deny`|`ask`). Вызывается в `agent-loop.ts` ПЕРЕД
134
- каждым инструментом: `deny` блокирует вызов, `ask` спрашивает оператора через
135
- `onAskPermission` (в TTY — интерактивный промпт над инпут-линией, в non-TTY —
136
- запрет). Новый чистый модуль `src/permissions.ts` + тесты
137
- (test/permissions.test.ts, test/permissions-loop.test.ts).
138
-
139
- - Кастомные команды: аргументы и подсказки (BACKLOG B7). Frontmatter
140
- `argument-hint:` показывается в списке «/» и в `/help` (не вставляется в
141
- строку ввода), а `arguments:` объявляет обязательные позиционные аргументы.
142
- В теле команды подставляются `$1 $2`, именованные `$name`, а также прежние
143
- `{{args}}`/`$ARGUMENTS`. Если обязательные аргументы не переданы — команда
144
- не уходит в чат, печатается подсказка. Новые чистые хелперы
215
+ - Real action approvals (BACKLOG C1): an approval policy in
216
+ `.zames/permissions.json` (`default` + `rules` with regexp on
217
+ `tool`/`command`/`path` and an `allow`|`deny`|`ask` action). Evaluated in
218
+ `agent-loop.ts` BEFORE every tool: `deny` blocks the call, `ask` prompts the
219
+ operator via `onAskPermission` (in a TTY — an interactive prompt above the
220
+ input line, in non-TTY — denied). New pure module `src/permissions.ts` +
221
+ tests (test/permissions.test.ts, test/permissions-loop.test.ts).
222
+
223
+ - Custom commands: arguments and hints (BACKLOG B7). Frontmatter
224
+ `argument-hint:` is shown in the "/" list and in `/help` (not inserted into
225
+ the input line), and `arguments:` declares mandatory positional arguments.
226
+ `$1 $2`, named `$name` and the previous `{{args}}`/`$ARGUMENTS` are
227
+ substituted into the command body. If the required arguments are missing the
228
+ command is not sent to the chat and a hint is printed. New pure helpers
145
229
  `splitCommandArgs()` / `expandCommandArgs()` / `missingCommandArgs()`
146
- (src/commands.ts, покрыты тестами).
147
-
148
- - Path-scoped правила (BACKLOG B6): вложенные `AGENTS.md`/`MEMORY.md` из
149
- подпапок, которых касается задача, подтягиваются автоматически. Текст задачи
150
- сканируется на path-токены, для найденных директорий (и их предков ниже
151
- рабочей) читаются ближайшие инструкции и рендерятся отдельной секцией
152
- `## Scoped instructions (...)` — явно помечены как действующие только для
153
- этих файлов. `loadProjectContext(workdir, touchPaths?)` и
154
- `renderContextSection()` (src/context.ts, src/system-prompt.ts; покрыто
155
- тестами).
156
-
157
- - `@file`-ссылки в задаче (BACKLOG B5): `реши задачу @src/browser.ts`
158
- подставляет содержимое указанного файла прямо в задачу, экономя отдельный
159
- ход агента на чтение. Распознаётся `@path` на границе слова (в начале строки
160
- или после пробела/скобки/кавычки), с расширением файла; `user@host` и
161
- декораторы (`@Component`) не трогаются. Существующие файлы инлайнятся
162
- (лимит 60 КБ на файл, 200 КБ суммарно — сверх этого усечение с пометкой),
163
- несуществующие остаются как есть. Хелпер `extractAtFileRefs()` в
164
- `src/path-token.ts` (чистый, покрыт тестами).
230
+ (src/commands.ts, unit-tested).
231
+
232
+ - Path-scoped rules (BACKLOG B6): nested `AGENTS.md`/`MEMORY.md` from the
233
+ subdirectories the task touches are pulled in automatically. The task text is
234
+ scanned for path tokens, the nearest instructions are read for the found
235
+ directories (and their ancestors below the working dir) and rendered as a
236
+ separate `## Scoped instructions (...)` section — explicitly marked as
237
+ applying only to those files. `loadProjectContext(workdir, touchPaths?)` and
238
+ `renderContextSection()` (src/context.ts, src/system-prompt.ts; unit-tested).
239
+
240
+ - `@file` references in a task (BACKLOG B5): `solve the task @src/browser.ts`
241
+ inlines the contents of the referenced file right into the task, saving a
242
+ separate agent turn to read it. `@path` is recognized at a word boundary (at
243
+ the start of a line or after a space/bracket/quote) with a file extension;
244
+ `user@host` and decorators (`@Component`) are not touched. Existing files are
245
+ inlined (60 KB per file, 200 KB total — beyond that a truncation marker),
246
+ missing ones stay as-is. Helper `extractAtFileRefs()` in `src/path-token.ts`
247
+ (pure, unit-tested).
165
248
 
166
249
  ### Changed
167
250
 
168
- - `AGENTS.md` уменьшен (BACKLOG C2): глубокие root-cause разборы («агент
169
- остановился», чтение ответа из DOM, send-хуки, `LineEditor`, вложения) и
170
- терминальная механика вынесены в `docs/DESIGN-NOTES.md` (progressive
171
- disclosure — не грузится в каждую задачу). В AGENTS.md остались действующие
172
- правила и краткая выжимка со ссылкой.
251
+ - `AGENTS.md` trimmed (BACKLOG C2): the deep root-cause write-ups ("the agent
252
+ stopped", reading the answer from the DOM, send hooks, `LineEditor`,
253
+ attachments) and the terminal mechanics were moved to
254
+ `docs/DESIGN-NOTES.md` (progressive disclosure — not loaded into every task).
255
+ AGENTS.md keeps the acting rules plus a short summary with a pointer.
173
256
 
174
257
  ## [2.62.0]
175
258