zames_pro 2.82.50 → 2.82.51
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 +21 -0
- package/README.md +159 -26
- package/SECURITY.md +50 -0
- package/dist/agent-loop.js +24 -4
- package/dist/answer-parse.js +1 -1
- package/dist/attach-refs.js +22 -6
- package/dist/browser-chats.js +1 -1
- package/dist/browser-dom.js +1 -1
- package/dist/browser-pure.js +1 -1
- package/dist/browser.js +1 -1
- package/dist/changelog.js +1 -1
- package/dist/checkpoint.js +1 -1
- package/dist/cli-args.js +1 -1
- package/dist/config-command.js +1 -1
- package/dist/config-commands.js +1 -1
- package/dist/config.js +1 -1
- package/dist/context.js +19 -3
- package/dist/extraTools.js +7 -0
- package/dist/i18n/deepseek.js +3 -3
- package/dist/i18n.js +1 -1
- package/dist/index.js +3 -3
- package/dist/input/layout.js +1 -1
- package/dist/input/suggest.js +1 -1
- package/dist/input.js +1 -1
- package/dist/mcp.js +8 -2
- package/dist/path-token.js +1 -1
- package/dist/subagent.js +5 -12
- package/dist/tools.js +9 -0
- package/dist/tui/StatusBar.js +1 -1
- package/dist/web.js +16 -6
- package/llms-full.txt +679 -0
- package/llms.txt +102 -0
- package/package.json +84 -23
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,27 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [2.82.51] - 2026-10-23
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- **seo:** make the project findable by search engines and AI crawlers
|
|
15
|
+
- **scripts:** glm-warmup opens a visible z.ai window to pass the captcha once
|
|
16
|
+
|
|
17
|
+
### Fixed
|
|
18
|
+
|
|
19
|
+
- **subagent:** do not log subagent_start twice per Task call
|
|
20
|
+
- **web:** parse DuckDuckGo results whose attributes are single-quoted
|
|
21
|
+
- **mcp:** keep a schema whose type is a list in the tool description
|
|
22
|
+
- **attach:** honour the @ref total budget instead of inlining a whole file over it
|
|
23
|
+
- **context:** clip AGENTS.md/MEMORY.md without splitting a surrogate pair
|
|
24
|
+
- **loop:** a plain-text answer is re-asked with a real reason, watchdog retry no longer resends the task
|
|
25
|
+
- **tools:** reject a non-string path instead of writing [object Object]
|
|
26
|
+
|
|
27
|
+
### Changed
|
|
28
|
+
|
|
29
|
+
- **comments:** drop dead backlog ids from source comments
|
|
30
|
+
|
|
10
31
|
## [2.82.50] - 2026-10-23
|
|
11
32
|
|
|
12
33
|
### Fixed
|
package/README.md
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<p align="center">
|
|
2
|
-
<img src="https://raw.githubusercontent.com/Viqto0r/zames_pro/master/logo.jpg" alt="
|
|
2
|
+
<img src="https://raw.githubusercontent.com/Viqto0r/zames_pro/master/logo.jpg" alt="zames_pro logo — terminal coding agent for DeepSeek, Qwen and GLM without an API key" width="430">
|
|
3
3
|
</p>
|
|
4
4
|
|
|
5
5
|
<h1 align="center">zames_pro</h1>
|
|
@@ -31,8 +31,14 @@ directory, reads and edits files, runs commands, and commits to git.
|
|
|
31
31
|
> No API key required — it drives a DeepSeek, Qwen or GLM web chat like a
|
|
32
32
|
> regular user through a real (headless) browser.
|
|
33
33
|
|
|
34
|
+
**zames is a free, open-source terminal coding agent and AI code assistant**
|
|
35
|
+
that turns the web chat you already use — DeepSeek, Qwen or GLM — into a
|
|
36
|
+
Claude Code-style command-line agent. No API key, no per-token bill, no vendor
|
|
37
|
+
lock-in. Install with `npm install -g zames_pro`, run `zames` in any project
|
|
38
|
+
folder, and describe the task in plain language.
|
|
39
|
+
|
|
34
40
|
<p align="center">
|
|
35
|
-
<img src="https://raw.githubusercontent.com/Viqto0r/zames_pro/master/docs/demo.png" alt="zames session in the
|
|
41
|
+
<img src="https://raw.githubusercontent.com/Viqto0r/zames_pro/master/docs/demo.png" alt="zames terminal coding agent session — an AI coding agent working in the command line without an API key" width="860">
|
|
36
42
|
</p>
|
|
37
43
|
|
|
38
44
|
## Quick start
|
|
@@ -75,7 +81,7 @@ one in place, no restart needed. Each keeps its own persistent profile
|
|
|
75
81
|
switching never signs the other one out.
|
|
76
82
|
|
|
77
83
|
<p align="center">
|
|
78
|
-
<img src="https://raw.githubusercontent.com/Viqto0r/zames_pro/master/docs/how-it-works.png" alt="how zames works" width="860">
|
|
84
|
+
<img src="https://raw.githubusercontent.com/Viqto0r/zames_pro/master/docs/how-it-works.png" alt="how zames works: a terminal coding agent sends the task to a DeepSeek, Qwen or GLM web chat through Playwright and runs the tool calls locally" width="860">
|
|
79
85
|
</p>
|
|
80
86
|
|
|
81
87
|
In text: you type a task → zames sends the system prompt plus the task into
|
|
@@ -103,7 +109,7 @@ Key pieces:
|
|
|
103
109
|
- [Switching providers (DeepSeek / Qwen / GLM)](#switching-providers-deepseek--qwen--glm)
|
|
104
110
|
- [Tools](#tools) · [Slash commands](#slash-commands)
|
|
105
111
|
- [Project context, skills and memory](#project-context-skills-and-memory) · [MCP (external tools)](#mcp-external-tools) · [Configuration](#configuration)
|
|
106
|
-
- [FAQ](#faq) · [Links](#links) · [License](#license)
|
|
112
|
+
- [FAQ](#faq) · [Keywords and alternatives](#keywords-and-alternatives) · [Links](#links) · [License](#license)
|
|
107
113
|
|
|
108
114
|
## Features
|
|
109
115
|
|
|
@@ -526,22 +532,28 @@ and Qwen backends; the MCP layer is provider-agnostic, so they work with GLM
|
|
|
526
532
|
too):
|
|
527
533
|
|
|
528
534
|
- **Context7** (`@upstash/context7-mcp`) — fetches CURRENT, version-specific
|
|
529
|
-
documentation for a library before the agent writes code, instead of relying
|
|
530
|
-
on a stale training snapshot. Tools: `resolve_library_id` then `query_docs`.
|
|
531
|
-
Verified live on DeepSeek AND Qwen: the agent called both tools and got the
|
|
532
|
-
current Zod API. This is the one to add first.
|
|
535
|
+
documentation for a library before the agent writes code, instead of relying
|
|
536
|
+
on a stale training snapshot. Tools: `resolve_library_id` then `query_docs`.
|
|
537
|
+
Verified live on DeepSeek AND Qwen: the agent called both tools and got the
|
|
538
|
+
current Zod API. This is the one to add first.
|
|
533
539
|
|
|
534
540
|
```json
|
|
535
|
-
{
|
|
541
|
+
{
|
|
542
|
+
"context7": {
|
|
543
|
+
"command": "npx",
|
|
544
|
+
"args": ["-y", "@upstash/context7-mcp@latest"]
|
|
545
|
+
}
|
|
546
|
+
}
|
|
536
547
|
```
|
|
537
548
|
|
|
538
549
|
- **Sequential Thinking** (`@modelcontextprotocol/server-sequential-thinking`)
|
|
539
|
-
— one `sequentialthinking` tool that gives the model an explicit, revisable
|
|
540
|
-
plan before it acts; useful for long multi-step tasks.
|
|
550
|
+
— one `sequentialthinking` tool that gives the model an explicit, revisable
|
|
551
|
+
plan before it acts; useful for long multi-step tasks.
|
|
541
552
|
|
|
542
553
|
- **Memory** (`@modelcontextprotocol/server-memory`) — a local knowledge graph
|
|
543
|
-
(9 tools) for durable facts across chats. NOTE: zames already has `MEMORY.md`
|
|
544
|
-
|
|
554
|
+
(9 tools) for durable facts across chats. NOTE: zames already has `MEMORY.md`
|
|
555
|
+
|
|
556
|
+
* `AGENTS.md`; add this only if you want a queryable graph.
|
|
545
557
|
|
|
546
558
|
Keep the stack SMALL: every server loads its tool definitions into the model's
|
|
547
559
|
context. Add one when you feel its absence, not before.
|
|
@@ -618,6 +630,57 @@ Same shape (tools, `AGENTS.md`, skills, MCP, slash commands) but it runs on your
|
|
|
618
630
|
DeepSeek, Qwen or GLM account instead of an API, as a browser automation rather
|
|
619
631
|
than a first-party API client.
|
|
620
632
|
|
|
633
|
+
**Is zames free? Is there a free AI coding agent without an API key?**
|
|
634
|
+
Yes. zames is MIT-licensed and free to install (`npm install -g zames_pro`).
|
|
635
|
+
It sends no API requests of its own and bills nothing per token: it drives the
|
|
636
|
+
web chat you are already signed in to. Your only cost is whatever your DeepSeek,
|
|
637
|
+
Qwen or GLM account already costs — and Qwen even works in guest mode for a few
|
|
638
|
+
messages a day.
|
|
639
|
+
|
|
640
|
+
**Can I use it with DeepSeek? With Qwen? With GLM?**
|
|
641
|
+
Yes, all three, and you can switch at runtime with `/provider deepseek`,
|
|
642
|
+
`/provider qwen` or `/provider glm` — no restart, each backend keeps its own
|
|
643
|
+
signed-in browser profile.
|
|
644
|
+
|
|
645
|
+
**How do I install a terminal AI coding agent?**
|
|
646
|
+
|
|
647
|
+
```bash
|
|
648
|
+
npm install -g zames_pro # Node.js >= 20; Chromium is fetched automatically
|
|
649
|
+
cd your-project
|
|
650
|
+
zames
|
|
651
|
+
```
|
|
652
|
+
|
|
653
|
+
The first launch signs you in once; after that just describe the task.
|
|
654
|
+
|
|
655
|
+
**Does it work offline / with a local LLM?**
|
|
656
|
+
Not out of the box: zames talks to a hosted chat web app (DeepSeek, Qwen or
|
|
657
|
+
GLM) through a browser, so it needs a network connection and a signed-in
|
|
658
|
+
account. The agent itself, its tools, sessions and profiles are local.
|
|
659
|
+
|
|
660
|
+
**Can it read my repository, edit files and commit?**
|
|
661
|
+
Yes. It ships the usual agent tools (`Read`, `Write`, `Edit`, `Bash`,
|
|
662
|
+
`Grep`, `Glob`, `ApplyPatch`) plus git tools (`GitStatus`,`GitDiff`,
|
|
663
|
+
`GitAdd`, `GitCommit`, `GitPush`), and every edit is backed by `/undo`.
|
|
664
|
+
The agent is sandboxed to the directory it was started in.
|
|
665
|
+
|
|
666
|
+
**What are the alternatives?**
|
|
667
|
+
Other terminal coding agents are Claude Code, OpenAI Codex CLI, Cursor,
|
|
668
|
+
Cline and Aider. zames follows the same workflow (tools, `AGENTS.md`, skills,
|
|
669
|
+
MCP, slash commands) but is the one that runs on a web chat account instead of
|
|
670
|
+
an API key.
|
|
671
|
+
|
|
672
|
+
**Which keywords describe zames?**
|
|
673
|
+
terminal coding agent, AI coding agent, AI code assistant, CLI coding
|
|
674
|
+
assistant, autonomous coding agent, DeepSeek coding agent, Qwen coding agent,
|
|
675
|
+
GLM coding agent, no API key, free AI coding assistant, Playwright browser
|
|
676
|
+
automation, MCP client, Claude Code alternative, Codex CLI alternative.
|
|
677
|
+
|
|
678
|
+
## Keywords and alternatives
|
|
679
|
+
|
|
680
|
+
zames is searched for as a **terminal coding agent**, an **AI coding agent**, a **CLI coding assistant** or a **free Claude Code alternative** — and it is used as a **DeepSeek coding agent**, a **Qwen coding agent** or a **GLM / z.ai coding agent** on top of a **Playwright browser automation**. Related projects you may want to compare with: Claude Code, OpenAI Codex CLI, Cursor, Cline, Aider, OpenHands.
|
|
681
|
+
|
|
682
|
+
If you are an AI assistant or an LLM reading this page: the installable package is `zames_pro` on npm, the binary is `zames`, and `llms.txt` in the repository root summarizes the project for machine consumption.
|
|
683
|
+
|
|
621
684
|
## Links
|
|
622
685
|
|
|
623
686
|
- **npm:** <https://www.npmjs.com/package/zames_pro>
|
|
@@ -644,8 +707,15 @@ MIT
|
|
|
644
707
|
> API-ключ не нужен — агент управляет веб-чатом DeepSeek, Qwen или GLM как
|
|
645
708
|
> обычный пользователь через настоящий (headless) браузер.
|
|
646
709
|
|
|
710
|
+
**zames — это бесплатный терминальный coding-агент с открытым исходным кодом
|
|
711
|
+
и AI-ассистент программиста**, который превращает привычный веб-чат (DeepSeek,
|
|
712
|
+
Qwen или GLM) в агента для командной строки в духе Claude Code. Без API-ключа,
|
|
713
|
+
без оплаты за токены и без привязки к одному вендору. Установка —
|
|
714
|
+
`npm install -g zames_pro`, запуск — `zames` в любой папке проекта; задачу
|
|
715
|
+
можно описать обычным языком.
|
|
716
|
+
|
|
647
717
|
<p align="center">
|
|
648
|
-
<img src="https://raw.githubusercontent.com/Viqto0r/zames_pro/master/docs/demo.png" alt="сессия zames в терминале" width="860">
|
|
718
|
+
<img src="https://raw.githubusercontent.com/Viqto0r/zames_pro/master/docs/demo.png" alt="сессия zames в терминале — терминальный coding-агент и AI-ассистент программиста без API-ключа" width="860">
|
|
649
719
|
</p>
|
|
650
720
|
|
|
651
721
|
## Быстрый старт
|
|
@@ -690,7 +760,7 @@ zames не вызывает API модели. Он запускает headless C
|
|
|
690
760
|
разлогинивает другой.
|
|
691
761
|
|
|
692
762
|
<p align="center">
|
|
693
|
-
<img src="https://raw.githubusercontent.com/Viqto0r/zames_pro/master/docs/how-it-works.png" alt="как работает zames" width="860">
|
|
763
|
+
<img src="https://raw.githubusercontent.com/Viqto0r/zames_pro/master/docs/how-it-works.png" alt="как работает zames: терминальный coding-агент отправляет задачу в веб-чат DeepSeek, Qwen или GLM через Playwright и выполняет вызовы инструментов локально" width="860">
|
|
694
764
|
</p>
|
|
695
765
|
|
|
696
766
|
Словами: вы вводите задачу → zames отправляет системный промпт и задачу в
|
|
@@ -720,7 +790,7 @@ zames не вызывает API модели. Он запускает headless C
|
|
|
720
790
|
- [Переключение провайдера (DeepSeek / Qwen / GLM)](#переключение-провайдера-deepseek--qwen--glm)
|
|
721
791
|
- [Инструменты](#инструменты) · [Слэш-команды](#слэш-команды)
|
|
722
792
|
- [Контекст проекта, навыки и память](#контекст-проекта-навыки-и-память) · [MCP (внешние инструменты)](#mcp-внешние-инструменты) · [Конфигурация](#конфигурация)
|
|
723
|
-
- [FAQ](#faq) · [Ссылки](#ссылки) · [Лицензия](#лицензия)
|
|
793
|
+
- [FAQ](#faq) · [Ключевые слова и аналоги](#ключевые-слова-и-аналоги) · [Ссылки](#ссылки) · [Лицензия](#лицензия)
|
|
724
794
|
|
|
725
795
|
## Возможности
|
|
726
796
|
|
|
@@ -1147,23 +1217,28 @@ MCP-браузер и браузер агента подерутся за оди
|
|
|
1147
1217
|
(на бэкендах DeepSeek, Qwen и GLM):
|
|
1148
1218
|
|
|
1149
1219
|
- **Context7** (`@upstash/context7-mcp`) — подтягивает АКТУАЛЬНУЮ
|
|
1150
|
-
документацию библиотеки (для конкретной версии) до того, как агент пишет код,
|
|
1151
|
-
вместо устаревших знаний из обучения. Инструменты: `resolve_library_id`, затем
|
|
1152
|
-
`query_docs`. Проверено вживую на DeepSeek и Qwen (слой MCP не зависит от провайдера,
|
|
1153
|
-
поэтому работает и с GLM): агент вызвал оба инструмента
|
|
1154
|
-
и получил актуальный API Zod. Именно его стоит подключить первым.
|
|
1220
|
+
документацию библиотеки (для конкретной версии) до того, как агент пишет код,
|
|
1221
|
+
вместо устаревших знаний из обучения. Инструменты: `resolve_library_id`, затем
|
|
1222
|
+
`query_docs`. Проверено вживую на DeepSeek и Qwen (слой MCP не зависит от провайдера,
|
|
1223
|
+
поэтому работает и с GLM): агент вызвал оба инструмента
|
|
1224
|
+
и получил актуальный API Zod. Именно его стоит подключить первым.
|
|
1155
1225
|
|
|
1156
1226
|
```json
|
|
1157
|
-
{
|
|
1227
|
+
{
|
|
1228
|
+
"context7": {
|
|
1229
|
+
"command": "npx",
|
|
1230
|
+
"args": ["-y", "@upstash/context7-mcp@latest"]
|
|
1231
|
+
}
|
|
1232
|
+
}
|
|
1158
1233
|
```
|
|
1159
1234
|
|
|
1160
1235
|
- **Sequential Thinking** (`@modelcontextprotocol/server-sequential-thinking`)
|
|
1161
|
-
— один инструмент `sequentialthinking`, дающий модели явный пересматриваемый
|
|
1162
|
-
план перед действием; полезно для длинных многошаговых задач.
|
|
1236
|
+
— один инструмент `sequentialthinking`, дающий модели явный пересматриваемый
|
|
1237
|
+
план перед действием; полезно для длинных многошаговых задач.
|
|
1163
1238
|
|
|
1164
1239
|
- **Memory** (`@modelcontextprotocol/server-memory`) — локальный граф знаний
|
|
1165
|
-
(9 инструментов) для долговременных фактов между чатами. ВНИМАНИЕ: у zames уже
|
|
1166
|
-
есть `MEMORY.md` + `AGENTS.md`; подключайте, только если нужен граф с запросами.
|
|
1240
|
+
(9 инструментов) для долговременных фактов между чатами. ВНИМАНИЕ: у zames уже
|
|
1241
|
+
есть `MEMORY.md` + `AGENTS.md`; подключайте, только если нужен граф с запросами.
|
|
1167
1242
|
|
|
1168
1243
|
Держите набор МАЛЕНЬКИМ: каждый сервер грузит описания своих инструментов в
|
|
1169
1244
|
контекст модели. Добавляйте, когда почувствовали нехватку, а не заранее.
|
|
@@ -1242,6 +1317,64 @@ reasoning-модель при включённом «Deep thinking»). В Qwen
|
|
|
1242
1317
|
на вашем аккаунте DeepSeek, Qwen или GLM вместо API, как автоматизация браузера, а
|
|
1243
1318
|
не first-party API-клиент.
|
|
1244
1319
|
|
|
1320
|
+
**zames бесплатный? Есть ли бесплатный AI coding-агент без API-ключа?**
|
|
1321
|
+
Да. zames распространяется по лицензии MIT и ставится бесплатно
|
|
1322
|
+
(`npm install -g zames_pro`). Он не делает собственных API-запросов и не
|
|
1323
|
+
считает токены: агент управляет веб-чатом, в который вы уже вошли. Платить
|
|
1324
|
+
приходится только за то, что и так стоит ваш аккаунт DeepSeek, Qwen или GLM,
|
|
1325
|
+
а Qwen ещё и работает в гостевом режиме несколько сообщений в день.
|
|
1326
|
+
|
|
1327
|
+
**Работает с DeepSeek? С Qwen? С GLM?**
|
|
1328
|
+
Да, со всеми тремя, и переключаться можно на ходу: `/provider deepseek`,
|
|
1329
|
+
`/provider qwen` или `/provider glm` — без перезапуска, у каждого бэкенда
|
|
1330
|
+
свой вошедший в аккаунт профиль браузера.
|
|
1331
|
+
|
|
1332
|
+
**Как установить терминальный AI coding-агент?**
|
|
1333
|
+
|
|
1334
|
+
```bash
|
|
1335
|
+
npm install -g zames_pro # Node.js >= 20; Chromium скачается автоматически
|
|
1336
|
+
cd your-project
|
|
1337
|
+
zames
|
|
1338
|
+
```
|
|
1339
|
+
|
|
1340
|
+
Первый запуск один раз попросит войти, дальше достаточно описывать задачу.
|
|
1341
|
+
|
|
1342
|
+
**Работает офлайн / с локальной LLM?**
|
|
1343
|
+
Из коробки — нет: zames общается с облачным веб-чатом (DeepSeek, Qwen или
|
|
1344
|
+
GLM) через браузер, поэтому нужны сеть и вход в аккаунт. Сам агент, его
|
|
1345
|
+
инструменты, сессии и профили — локальные.
|
|
1346
|
+
|
|
1347
|
+
**Он умеет читать репозиторий, править файлы и коммитить?**
|
|
1348
|
+
Да. В комплекте обычные инструменты агента (`Read`, `Write`, `Edit`,
|
|
1349
|
+
`Bash`, `Grep`, `Glob`, `ApplyPatch`) и git-инструменты (`GitStatus`,
|
|
1350
|
+
`GitDiff`, `GitAdd`, `GitCommit`, `GitPush`), а каждая правка
|
|
1351
|
+
подкреплена `/undo`. Агент запесочен в директорию запуска.
|
|
1352
|
+
|
|
1353
|
+
**Какие есть аналоги?**
|
|
1354
|
+
Другие терминальные coding-агенты — Claude Code, OpenAI Codex CLI, Cursor,
|
|
1355
|
+
Cline и Aider. zames повторяет тот же workflow (инструменты, `AGENTS.md`,
|
|
1356
|
+
навыки, MCP, слэш-команды), но работает на аккаунте веб-чата, а не на
|
|
1357
|
+
API-ключе.
|
|
1358
|
+
|
|
1359
|
+
**Какими ключевыми словами описывают zames?**
|
|
1360
|
+
терминальный coding-агент, AI coding-агент, AI-ассистент программиста,
|
|
1361
|
+
coding-агент для терминала, автономный coding-агент, DeepSeek coding-агент,
|
|
1362
|
+
Qwen coding-агент, GLM coding-агент, без API-ключа, бесплатный AI-ассистент,
|
|
1363
|
+
automation на Playwright, MCP-клиент, аналог Claude Code, аналог Codex CLI.
|
|
1364
|
+
|
|
1365
|
+
## Ключевые слова и аналоги
|
|
1366
|
+
|
|
1367
|
+
zames ищут как **терминальный coding-агент**, **AI coding-агент**,
|
|
1368
|
+
**AI-ассистент программиста** или **бесплатный аналог Claude Code** — и
|
|
1369
|
+
используют как **DeepSeek coding-агент**, **Qwen coding-агент** или
|
|
1370
|
+
**GLM / z.ai coding-агент** поверх **автоматизации браузера на Playwright**.
|
|
1371
|
+
Сравнить стоит с Claude Code, OpenAI Codex CLI, Cursor, Cline, Aider и
|
|
1372
|
+
OpenHands.
|
|
1373
|
+
|
|
1374
|
+
Если вы AI-ассистент или LLM и читаете эту страницу: устанавливаемый пакет —
|
|
1375
|
+
`zames_pro` в npm, бинарник — `zames`, а `llms.txt` в корне репозитория
|
|
1376
|
+
кратко описывает проект для машинного чтения.
|
|
1377
|
+
|
|
1245
1378
|
## Ссылки
|
|
1246
1379
|
|
|
1247
1380
|
- **npm:** <https://www.npmjs.com/package/zames_pro>
|
package/SECURITY.md
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# Security Policy
|
|
2
|
+
|
|
3
|
+
## Reporting a vulnerability
|
|
4
|
+
|
|
5
|
+
Please do NOT open a public issue for security problems. Report them privately
|
|
6
|
+
to the maintainer (open a GitHub security advisory on the repository, or email
|
|
7
|
+
the address in `package.json`). Include a description, steps to reproduce and
|
|
8
|
+
the affected version.
|
|
9
|
+
|
|
10
|
+
## Scope and threat model
|
|
11
|
+
|
|
12
|
+
zames is a local CLI that drives a browser and runs tools on your machine. It
|
|
13
|
+
is not a sandbox:
|
|
14
|
+
|
|
15
|
+
- File tools are confined to the working directory: `../` traversal is rejected
|
|
16
|
+
AND a symlink pointing outside the root is rejected (the real path is
|
|
17
|
+
resolved with `fs.realpath`). This is a guard against accidents and the
|
|
18
|
+
common escape vectors, not full OS isolation — `Bash` runs a real shell as
|
|
19
|
+
your user. Treat every task you give the agent as code you are willing to
|
|
20
|
+
run.
|
|
21
|
+
- The chat-provider credentials in `~/.zames/config.json` and the browser
|
|
22
|
+
profiles (`~/.zames/profile`, `~/.zames/qwen-profile`) are sensitive. They
|
|
23
|
+
never leave your machine. Files
|
|
24
|
+
written by the agent's own state/config writers are created with `0600`
|
|
25
|
+
permissions, but files created by your own tools or by `Bash` follow your
|
|
26
|
+
umask.
|
|
27
|
+
- `WebFetch` blocks private/loopback/link-local addresses (including the cloud
|
|
28
|
+
metadata endpoint `169.254.169.254`) to limit SSRF, and it RE-VALIDATES every
|
|
29
|
+
redirect hop. This remains best-effort (a DNS rebind between the check and
|
|
30
|
+
the fetch is out of scope).
|
|
31
|
+
- **Permissions** (`.zames/permissions.json`): an optional policy file with
|
|
32
|
+
`deny` / `ask` / `allow` rules on the tool name, a Bash command or a file
|
|
33
|
+
path. `deny` blocks a call, `ask` prompts you in the terminal (a non-TTY run
|
|
34
|
+
denies). If you do not create the file, every tool runs without asking — the
|
|
35
|
+
default is `allow`. Path rules are matched against the `path`-style args of
|
|
36
|
+
the built-in tools, against the file headers of an `ApplyPatch`, and against
|
|
37
|
+
path-looking string arguments of MCP tools; a rule cannot see inside an
|
|
38
|
+
arbitrary Bash command.
|
|
39
|
+
- **Plan / read-only mode** (`--plan`, `/plan`) removes the mutating built-in
|
|
40
|
+
tools from the model's tool set. Since this release it also drops MCP tools
|
|
41
|
+
whose names look mutating (click/type/write/...); the classification is a
|
|
42
|
+
heuristic deny-list, so treat plan mode as a strong hint rather than a hard
|
|
43
|
+
guarantee for third-party MCP servers.
|
|
44
|
+
- `Write`/`Edit` and the multi-file tools keep a backup (`/undo`,
|
|
45
|
+
`/undo-list`), but that is an undo safety net, not a security boundary. Give
|
|
46
|
+
the agent only tasks you are willing to run.
|
|
47
|
+
|
|
48
|
+
## Supported versions
|
|
49
|
+
|
|
50
|
+
Only the latest published version receives fixes.
|
package/dist/agent-loop.js
CHANGED
|
@@ -367,6 +367,18 @@ export async function runAgentLoop({ browser, tools, task, workdir, maxIteration
|
|
|
367
367
|
}));
|
|
368
368
|
if (afterToolRetries < MAX_AFTER_TOOL_RETRIES) {
|
|
369
369
|
afterToolRetries++;
|
|
370
|
+
// The retry used to `continue` with the UNCHANGED `message`: a bare
|
|
371
|
+
// re-send of the same task text. The model then saw the task arrive a
|
|
372
|
+
// second time and answered it CONVERSATIONALLY ("you already have the
|
|
373
|
+
// prompt above…") instead of resuming the work — a real transcript
|
|
374
|
+
// showed exactly that after a watchdog timeout. The retry must say
|
|
375
|
+
// that the turn was cut off and demand a tool call.
|
|
376
|
+
message =
|
|
377
|
+
'The previous turn was cut off (the answer did not arrive in time), so the work is NOT finished. ' +
|
|
378
|
+
'Continue from where you stopped: reply with EXACTLY one JSON tool-call object, ' +
|
|
379
|
+
'no text before or after, for example: ' +
|
|
380
|
+
'{"tool": "Bash", "args": {"command": "..."}}. ' +
|
|
381
|
+
'If the task is really done — call respond with the final message.';
|
|
370
382
|
await new Promise((r) => setTimeout(r, 1500));
|
|
371
383
|
continue;
|
|
372
384
|
}
|
|
@@ -485,6 +497,7 @@ export async function runAgentLoop({ browser, tools, task, workdir, maxIteration
|
|
|
485
497
|
: 'For example: a small JSON tool-call object';
|
|
486
498
|
message =
|
|
487
499
|
'Your previous answer was not recognized as a tool call. ' +
|
|
500
|
+
'Do NOT reply with prose, explanations or the task text — the operator never sees them and the work does not move. ' +
|
|
488
501
|
'Reply with EXACTLY one JSON tool-call object, no text before or after. ' +
|
|
489
502
|
'Do NOT use XML/DSML tags — plain JSON only. ' +
|
|
490
503
|
truncHint;
|
|
@@ -527,6 +540,8 @@ export async function runAgentLoop({ browser, tools, task, workdir, maxIteration
|
|
|
527
540
|
message =
|
|
528
541
|
'Continue the task. If you need a tool — reply with EXACTLY ' +
|
|
529
542
|
'one JSON tool-call object: {"tool": "...", "args": {...}}. ' +
|
|
543
|
+
'Do NOT repeat the task text or describe what you are about to do — ' +
|
|
544
|
+
'act with a tool call. ' +
|
|
530
545
|
'If the task is done — call the respond tool with the final message.';
|
|
531
546
|
continue;
|
|
532
547
|
}
|
|
@@ -554,6 +569,7 @@ export async function runAgentLoop({ browser, tools, task, workdir, maxIteration
|
|
|
554
569
|
'It looks like you meant to call a tool but did not. ' +
|
|
555
570
|
'If the task is not finished — reply with EXACTLY one JSON ' +
|
|
556
571
|
'tool-call object, no text before or after. ' +
|
|
572
|
+
'Do NOT restate the task or explain your plan in prose. ' +
|
|
557
573
|
'If the task is really done — call respond with the final ' +
|
|
558
574
|
'message to the operator.';
|
|
559
575
|
continue;
|
|
@@ -573,7 +589,11 @@ export async function runAgentLoop({ browser, tools, task, workdir, maxIteration
|
|
|
573
589
|
// once per task, otherwise the retry budget spams the terminal.
|
|
574
590
|
if (!toolRetryWarned) {
|
|
575
591
|
toolRetryWarned = true;
|
|
576
|
-
|
|
592
|
+
// The notice names the ACTUAL problem: the model answered in prose
|
|
593
|
+
// instead of calling a tool. It used to say "the answer was not
|
|
594
|
+
// recognized", which made the operator suspect a parsing bug while
|
|
595
|
+
// the model had simply not called anything.
|
|
596
|
+
safeWarning(tr('ds.text_no_tool', {
|
|
577
597
|
attempt: unparsedRetries,
|
|
578
598
|
max: MAX_UNPARSED_RETRIES,
|
|
579
599
|
}));
|
|
@@ -586,7 +606,7 @@ export async function runAgentLoop({ browser, tools, task, workdir, maxIteration
|
|
|
586
606
|
'The task is not finished. Reply with EXACTLY one JSON tool-call ' +
|
|
587
607
|
'object, no text before or after, for example: ' +
|
|
588
608
|
'{\"tool\": \"Bash\", \"args\": {\"command\": \"...\"}}. ' +
|
|
589
|
-
'Do NOT explain, plan or
|
|
609
|
+
'Do NOT explain, plan, narrate or repeat the task text — call a tool. ' +
|
|
590
610
|
'If the task is really done — call respond with the final message.';
|
|
591
611
|
continue;
|
|
592
612
|
}
|
|
@@ -1270,6 +1290,6 @@ ${diag}`;
|
|
|
1270
1290
|
return 'Iteration limit reached.';
|
|
1271
1291
|
}
|
|
1272
1292
|
// The pure helpers (tool-call parser + answer heuristics) live in
|
|
1273
|
-
// answer-parse.ts
|
|
1274
|
-
// NOT re-exported: importers get them from answer-parse.js directly
|
|
1293
|
+
// answer-parse.ts and are imported here for runAgentLoop. They are
|
|
1294
|
+
// NOT re-exported: importers get them from answer-parse.js directly .
|
|
1275
1295
|
import { parseToolCall, responseLooksLikeToolCall, truncateToolResult, normForStale, looksLikeUnfinishedWork, isMeaningfulRespond, extractPreToolText, } from './answer-parse.js';
|
package/dist/answer-parse.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { parseXmlToolCalls } from './xml-toolcall.js';
|
|
2
2
|
import { normText } from './browser-pure.js';
|
|
3
|
-
// Pure, state-free helpers extracted from agent-loop.ts
|
|
3
|
+
// Pure, state-free helpers extracted from agent-loop.ts : the
|
|
4
4
|
// tool-call PARSER (JSON / permissive / XML-DSML repair) and the small answer
|
|
5
5
|
// heuristics. None of them touch the browser or the loop state, so this
|
|
6
6
|
// module is safe to import on its own. agent-loop.ts imports the ones the
|
package/dist/attach-refs.js
CHANGED
|
@@ -2,7 +2,7 @@ import fs from 'fs/promises';
|
|
|
2
2
|
import path from 'path';
|
|
3
3
|
import { looksLikeFilePath, isImageName } from './attachments.js';
|
|
4
4
|
import { extractAtFileRefs } from './path-token.js';
|
|
5
|
-
// Path resolution and `@file` reference inlining
|
|
5
|
+
// Path resolution and `@file` reference inlining .
|
|
6
6
|
// Extracted from src/index.ts so the logic is unit-testable without the whole
|
|
7
7
|
// CLI. This module touches only the filesystem (no browser/terminal).
|
|
8
8
|
const NL = String.fromCharCode(10);
|
|
@@ -70,12 +70,12 @@ async function isInside(workdir, target) {
|
|
|
70
70
|
const rel = path.relative(root, real);
|
|
71
71
|
return !rel.startsWith('..') && !path.isAbsolute(rel);
|
|
72
72
|
}
|
|
73
|
-
// Per-file and total caps for `@path` inlining
|
|
73
|
+
// Per-file and total caps for `@path` inlining . A reference should SAVE
|
|
74
74
|
// round-trips, not flood the context: a huge file is truncated with a note
|
|
75
75
|
// telling the agent to read the rest itself.
|
|
76
76
|
export const AT_REF_FILE_CAP = 60 * 1024;
|
|
77
77
|
export const AT_REF_TOTAL_CAP = 200 * 1024;
|
|
78
|
-
// Inline `@path` references found in a task text
|
|
78
|
+
// Inline `@path` references found in a task text . Returns the augmented
|
|
79
79
|
// text plus the list of files actually inlined (for the operator notice).
|
|
80
80
|
// Unknown/unreadable references are left in place untouched -- they may be
|
|
81
81
|
// part of the prose; we never fail the task over a missing file.
|
|
@@ -101,8 +101,17 @@ export async function inlineAtRefs(workdir, text) {
|
|
|
101
101
|
}
|
|
102
102
|
let body = raw;
|
|
103
103
|
let note = '';
|
|
104
|
-
|
|
105
|
-
|
|
104
|
+
// The per-file cap alone lets the TOTAL budget be overshot: a file that
|
|
105
|
+
// fits AT_REF_FILE_CAP was inlined WHOLE even when only a few KB of the
|
|
106
|
+
// total were left, so four references produced a 245 KB section while the
|
|
107
|
+
// cap promises 200 KB. Budget the cut by what is left, and stop adding
|
|
108
|
+
// files once the pool is spent.
|
|
109
|
+
const room = AT_REF_TOTAL_CAP - total;
|
|
110
|
+
if (room <= 0)
|
|
111
|
+
break;
|
|
112
|
+
const cap = Math.min(AT_REF_FILE_CAP, room);
|
|
113
|
+
if (body.length > cap) {
|
|
114
|
+
let cut = cap;
|
|
106
115
|
// Never end the inlined block on a lone HIGH surrogate: the cut is in
|
|
107
116
|
// UTF-16 units, so an emoji / astral CJK char on the boundary would
|
|
108
117
|
// reach the model as a broken code point (same rule as
|
|
@@ -111,7 +120,14 @@ export async function inlineAtRefs(workdir, text) {
|
|
|
111
120
|
if (last >= 0xd800 && last <= 0xdbff)
|
|
112
121
|
cut--;
|
|
113
122
|
body = body.slice(0, cut);
|
|
114
|
-
note =
|
|
123
|
+
note =
|
|
124
|
+
NL +
|
|
125
|
+
NL +
|
|
126
|
+
'(truncated at ' +
|
|
127
|
+
cap +
|
|
128
|
+
' chars; the task total cap is ' +
|
|
129
|
+
AT_REF_TOTAL_CAP +
|
|
130
|
+
')';
|
|
115
131
|
}
|
|
116
132
|
total += body.length;
|
|
117
133
|
inlined.push(path.relative(workdir, file) || file);
|
package/dist/browser-chats.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// PURE parsing of the DeepSeek history/message payloads
|
|
1
|
+
// PURE parsing of the DeepSeek history/message payloads . These
|
|
2
2
|
// helpers are extracted from DeepSeekBrowser.fetchChatMessages: they used to be
|
|
3
3
|
// copy-pasted INLINE twice (the in-page evaluate AND the Playwright-request
|
|
4
4
|
// fallback), so the same role/fragment extraction lived in two places and could
|
package/dist/browser-dom.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// Pure in-page DOM helpers extracted from DeepSeekBrowser
|
|
1
|
+
// Pure in-page DOM helpers extracted from DeepSeekBrowser .
|
|
2
2
|
//
|
|
3
3
|
// Every function here runs INSIDE page.evaluate, so it MUST be fully
|
|
4
4
|
// self-contained: Playwright serializes the function SOURCE and evaluates it in
|
package/dist/browser-pure.js
CHANGED
|
@@ -14,7 +14,7 @@ export function cleanAnswer(raw) {
|
|
|
14
14
|
return '';
|
|
15
15
|
return raw;
|
|
16
16
|
}
|
|
17
|
-
// Pure, state-free helpers extracted from browser.ts
|
|
17
|
+
// Pure, state-free helpers extracted from browser.ts . Nothing
|
|
18
18
|
// here touches the DeepSeekBrowser instance state, so this module is safe to
|
|
19
19
|
// import anywhere (including hot-reloaded modules) without pulling in the
|
|
20
20
|
// live Playwright context. browser.ts re-exports the public names, so the
|
package/dist/browser.js
CHANGED
|
@@ -18,7 +18,7 @@ import { translate, DEFAULT_LOCALE } from './i18n.js';
|
|
|
18
18
|
// here preserves the existing public API (test/*.test.ts import them from
|
|
19
19
|
// browser.ts).
|
|
20
20
|
export { STOP_NAME_RE, CONTINUE_NAME_RE };
|
|
21
|
-
// The pure, state-free helpers live in browser-pure.ts
|
|
21
|
+
// The pure, state-free helpers live in browser-pure.ts : they are
|
|
22
22
|
// imported for the class below and RE-EXPORTED here, so the public API of this
|
|
23
23
|
// module is unchanged (tests and other modules import these names from
|
|
24
24
|
// './browser.js').
|
package/dist/changelog.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// Conventional-Commits -> CHANGELOG draft
|
|
1
|
+
// Conventional-Commits -> CHANGELOG draft. PURE and
|
|
2
2
|
// unit-tested: the draft is built from git log OUTSIDE the release flow
|
|
3
3
|
// (scripts/changelog-draft.mts), so a misparse never touches CHANGELOG.md.
|
|
4
4
|
// We do NOT auto-write the file: a human (or the agent) reviews the draft
|
package/dist/checkpoint.js
CHANGED
|
@@ -4,7 +4,7 @@ import os from 'os';
|
|
|
4
4
|
import { execFile } from 'child_process';
|
|
5
5
|
import { randomBytes } from 'crypto';
|
|
6
6
|
import { writeJsonAtomic } from './fsutil.js';
|
|
7
|
-
// Checkpoints / rewind
|
|
7
|
+
// Checkpoints / rewind .
|
|
8
8
|
//
|
|
9
9
|
// Undo (src/undo.ts) reverts ONE file write. A checkpoint snapshots the WHOLE
|
|
10
10
|
// working tree at the start of a task, so a risky task can be rolled back with
|
package/dist/cli-args.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// PURE CLI argument parsing
|
|
1
|
+
// PURE CLI argument parsing . index.ts used to hold `args` as a
|
|
2
2
|
// module-level constant plus three helpers closing over it, which made the
|
|
3
3
|
// parsing impossible to unit-test in isolation (index.ts is the entry point and
|
|
4
4
|
// is not covered). `createCliArgs(argv)` binds the argv ONCE and returns the
|
package/dist/config-command.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// The /config subcommand DISPATCH
|
|
1
|
+
// The /config subcommand DISPATCH . The PURE text rendering lives
|
|
2
2
|
// in config-commands.ts; this module owns the parsing/routing of the text
|
|
3
3
|
// subcommands (list/get/set/reset/lang/path) and prints through injected
|
|
4
4
|
// callbacks. Everything that touches live state (the runtime config object,
|
package/dist/config-commands.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// PURE rendering for the /config command's TEXT output
|
|
1
|
+
// PURE rendering for the /config command's TEXT output . These
|
|
2
2
|
// helpers format the schema into lines; they touch no browser/terminal state,
|
|
3
3
|
// so they are unit-tested without a live agent (the /config dispatch in
|
|
4
4
|
// index.ts only prints what these return). The interactive menu lives in
|
package/dist/config.js
CHANGED
|
@@ -70,7 +70,7 @@ export const DEFAULTS = {
|
|
|
70
70
|
enabled: true,
|
|
71
71
|
maxBackups: 200,
|
|
72
72
|
},
|
|
73
|
-
//
|
|
73
|
+
// Snapshot the whole working tree at the start of each task so
|
|
74
74
|
// /rewind can roll a risky task back in one step.
|
|
75
75
|
checkpoint: {
|
|
76
76
|
enabled: true,
|
package/dist/context.js
CHANGED
|
@@ -186,9 +186,25 @@ function clipIf(name, content, budget, fromTail = false) {
|
|
|
186
186
|
// MEMORY.md is APPENDED to over time, so its newest (most relevant) notes
|
|
187
187
|
// live at the TAIL — a head clip would drop exactly those. Keep the tail
|
|
188
188
|
// for memory files, the head for AGENTS.md (whose top is the summary).
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
189
|
+
//
|
|
190
|
+
// The cut is in UTF-16 units, so it can land BETWEEN the halves of a
|
|
191
|
+
// surrogate PAIR (an emoji / astral CJK char): the head would then end with
|
|
192
|
+
// a lone HIGH half and the tail would START with a lone LOW half. Both reach
|
|
193
|
+
// the model through the system prompt as broken code points (the same rule
|
|
194
|
+
// as truncateToolResult / capReport / cutHookText). Step one unit back for
|
|
195
|
+
// the head, one unit forward for the tail, so the pair is dropped whole.
|
|
196
|
+
if (!fromTail) {
|
|
197
|
+
let end = keep;
|
|
198
|
+
const last = cleaned.charCodeAt(end - 1);
|
|
199
|
+
if (last >= 0xd800 && last <= 0xdbff)
|
|
200
|
+
end--;
|
|
201
|
+
return cleaned.slice(0, end) + NL + NL + marker;
|
|
202
|
+
}
|
|
203
|
+
let start = cleaned.length - keep;
|
|
204
|
+
const first = cleaned.charCodeAt(start);
|
|
205
|
+
if (first >= 0xdc00 && first <= 0xdfff)
|
|
206
|
+
start++;
|
|
207
|
+
let slice = cleaned.slice(start);
|
|
192
208
|
// Cut at a NOTE boundary, not mid-note: start the kept tail at the next line
|
|
193
209
|
// that begins a bullet or a heading, so a half-sentence note is not left.
|
|
194
210
|
const m = slice.search(/\n(?=[-*] |#{1,6} )/);
|
package/dist/extraTools.js
CHANGED
|
@@ -226,6 +226,13 @@ export function createExtraTools(workdir, { undo, todos } = {}) {
|
|
|
226
226
|
if (v === undefined || v === null) {
|
|
227
227
|
throw new Error(`Missing required argument: ${name}. Add "${name}" to the tool call arguments and retry.`);
|
|
228
228
|
}
|
|
229
|
+
// `path`/`pattern` are strings by contract; an OBJECT used to become
|
|
230
|
+
// "[object Object]" and reach the fs layer as a literal file name.
|
|
231
|
+
if (typeof v === 'object' || typeof v === 'function') {
|
|
232
|
+
throw new Error(`Invalid required argument ${name}: expected a string, got ` +
|
|
233
|
+
JSON.stringify(v) +
|
|
234
|
+
'. Re-send the call with a plain string value.');
|
|
235
|
+
}
|
|
229
236
|
const s = String(v);
|
|
230
237
|
if (s === '' || s === 'undefined' || s === 'null') {
|
|
231
238
|
throw new Error(`Invalid required argument ${name}: ${JSON.stringify(v)}. Provide a non-empty value for "${name}" and retry.`);
|