zames_pro 2.82.49 → 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 +60 -0
- package/README.md +159 -26
- package/SECURITY.md +50 -0
- package/dist/agent-loop.js +35 -5
- package/dist/answer-parse.js +1 -1
- package/dist/attach-flow.js +7 -3
- package/dist/attach-refs.js +30 -6
- package/dist/attachments.js +9 -0
- package/dist/browser-chats.js +9 -2
- package/dist/browser-dom.js +1 -1
- package/dist/browser-pure.js +9 -3
- 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 +5 -2
- package/dist/config-live.js +10 -0
- package/dist/config.js +13 -1
- package/dist/context-command.js +6 -0
- package/dist/context.js +27 -4
- package/dist/diff.js +52 -9
- package/dist/extraTools.js +7 -0
- package/dist/glm-chats.js +18 -1
- package/dist/glm-net-capture.js +23 -5
- package/dist/goal.js +6 -1
- package/dist/i18n/deepseek.js +3 -3
- package/dist/i18n/self-review.js +4 -0
- package/dist/i18n.js +8 -2
- package/dist/index.js +90 -101
- package/dist/input/layout.js +33 -8
- package/dist/input/suggest.js +1 -1
- package/dist/input.js +1 -1
- package/dist/limits-command.js +42 -0
- package/dist/mcp.js +23 -4
- package/dist/model-command.js +21 -0
- package/dist/path-token.js +36 -9
- package/dist/permissions.js +32 -3
- package/dist/provider-command.js +29 -0
- package/dist/provider-handoff.js +18 -1
- package/dist/queue-command.js +15 -0
- package/dist/qwen-chats.js +13 -6
- package/dist/qwen-net-capture.js +13 -6
- package/dist/resume-command.js +38 -0
- package/dist/send-telemetry.js +15 -3
- package/dist/send-throttle.js +3 -1
- package/dist/status-command.js +68 -0
- package/dist/subagent.js +5 -12
- package/dist/tool-summary.js +8 -1
- package/dist/tools.js +13 -1
- package/dist/tui/StatusBar.js +1 -1
- package/dist/tui/log-window.js +41 -4
- package/dist/undo.js +11 -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,66 @@ 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
|
+
|
|
31
|
+
## [2.82.50] - 2026-10-23
|
|
32
|
+
|
|
33
|
+
### Fixed
|
|
34
|
+
|
|
35
|
+
- **i18n:** a prototype member is not a translation
|
|
36
|
+
- **path-token:** split semicolon-separated @file lists
|
|
37
|
+
- **tui:** keep a tall log entry inside the viewport when scrolling
|
|
38
|
+
- **resume:** refuse a session owned by another provider
|
|
39
|
+
- **tui:** skip OSC sequences when measuring log rows
|
|
40
|
+
- **layout:** wrapToWidth keeps every line within the width
|
|
41
|
+
- **tools:** trim allowed-tools entries before matching
|
|
42
|
+
- **config:** getByPath must not walk the prototype chain
|
|
43
|
+
- **context:** strip a BOM before parsing the frontmatter
|
|
44
|
+
- **telemetry:** a provider id must not escape the log directory
|
|
45
|
+
- **throttle:** a non-finite retryAfterMs must not block forever
|
|
46
|
+
- **auth:** do not migrate a legacy GLM marker to deepseek
|
|
47
|
+
- **qwen:** accept a bare array under chat.history
|
|
48
|
+
- **qwen:** a quota_limit mention inside an answer is not a rate limit
|
|
49
|
+
- **glm:** a quota phrase inside an answer is not a quota error
|
|
50
|
+
- **glm:** order the restored dialogue by an ISO timestamp too
|
|
51
|
+
- **attach:** a throwing preview lookup must not abort the attach
|
|
52
|
+
- **handoff:** clear the side handoff files too
|
|
53
|
+
- **loop:** resolve a padded or upper-cased tool name
|
|
54
|
+
- **mcp:** honour a profile flag given inside the command
|
|
55
|
+
- **config:** re-derive the ask deadline when the answer timeout changes live
|
|
56
|
+
- **diff:** compare lines with an LCS instead of by position
|
|
57
|
+
- **goal:** a verdict must not match the head of a word
|
|
58
|
+
- **telemetry:** ignore a send event dated in the future
|
|
59
|
+
- **tui:** show a sandbox refusal as a failed tool call
|
|
60
|
+
- **config:** the list does not mask a whitespace-only password
|
|
61
|
+
- **attach:** never treat a URL as a local file path
|
|
62
|
+
- **chats:** reject a negative accumulated_token_usage on restore
|
|
63
|
+
- **qwen:** never return a thinking-phase object as the answer
|
|
64
|
+
- **glm:** reject a negative token usage
|
|
65
|
+
- **undo:** tolerate a corrupt undo index
|
|
66
|
+
- **permissions:** match a command rule in nested MCP args
|
|
67
|
+
- **status:** fall back to the default context window on an invalid limit
|
|
68
|
+
- **input:** count blank lines at the end of a paste
|
|
69
|
+
|
|
10
70
|
## [2.82.49] - 2026-10-22
|
|
11
71
|
|
|
12
72
|
### 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
|
}
|
|
@@ -958,7 +978,17 @@ export async function runAgentLoop({ browser, tools, task, workdir, maxIteration
|
|
|
958
978
|
}
|
|
959
979
|
continue;
|
|
960
980
|
}
|
|
961
|
-
|
|
981
|
+
// Resolve the tool name TOLERANTLY: the model pads it with spaces or
|
|
982
|
+
// a newline (`"tool": " Bash "`) and sometimes changes its case
|
|
983
|
+
// (`bash`). An exact match reported `Unknown tool: Bash ` and the model
|
|
984
|
+
// simply repeated the same call, burning the retry budget. The first
|
|
985
|
+
// exact match still wins, so a name that really is distinct is not
|
|
986
|
+
// merged.
|
|
987
|
+
const wantName = String(call.tool ?? '')
|
|
988
|
+
.trim()
|
|
989
|
+
.toLowerCase();
|
|
990
|
+
const tool = tools.find((t) => t.name === call.tool) ??
|
|
991
|
+
tools.find((t) => t.name.trim().toLowerCase() === wantName);
|
|
962
992
|
if (!tool) {
|
|
963
993
|
const err = `Unknown tool: ${call.tool}`;
|
|
964
994
|
safeToolResult(err);
|
|
@@ -1260,6 +1290,6 @@ ${diag}`;
|
|
|
1260
1290
|
return 'Iteration limit reached.';
|
|
1261
1291
|
}
|
|
1262
1292
|
// The pure helpers (tool-call parser + answer heuristics) live in
|
|
1263
|
-
// answer-parse.ts
|
|
1264
|
-
// 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 .
|
|
1265
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-flow.js
CHANGED
|
@@ -36,9 +36,13 @@ export async function awaitUploadPreview(page, names, timeoutMs) {
|
|
|
36
36
|
const deadline = Date.now() + timeoutMs;
|
|
37
37
|
while (Date.now() < deadline) {
|
|
38
38
|
for (const name of clean) {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
39
|
+
// The lookup itself can THROW synchronously (Playwright: "Execution
|
|
40
|
+
// context was destroyed" while the page navigates). `.catch` handles a
|
|
41
|
+
// rejected promise, not a synchronous throw — without the try/catch the
|
|
42
|
+
// error escaped into `_attachFiles` and the whole attach failed. A
|
|
43
|
+
// lookup error means "not visible yet", exactly like a failed count.
|
|
44
|
+
const n = await Promise.resolve()
|
|
45
|
+
.then(() => page.getByText(name, { exact: false }).count())
|
|
42
46
|
.catch(() => 0);
|
|
43
47
|
if (n > 0)
|
|
44
48
|
return;
|
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);
|
|
@@ -27,6 +27,14 @@ export async function resolveAttachPath(workdir, raw) {
|
|
|
27
27
|
s = s.slice(1, -1);
|
|
28
28
|
}
|
|
29
29
|
s = s.replace(/\\ /g, ' ');
|
|
30
|
+
// A URL is never a local file. `isImageName` alone would still accept
|
|
31
|
+
// `https://example.com/a.png` (it only looks at the extension), and the
|
|
32
|
+
// RELATIVE candidate `path.resolve(workdir, 'https://…')` then becomes
|
|
33
|
+
// `https:/…` — a project that happens to have such a directory silently
|
|
34
|
+
// attached the URL as a file. A URL preceded by prose words is covered too
|
|
35
|
+
// (the same rule as looksLikeFilePath).
|
|
36
|
+
if (/(?:^|\s)[A-Za-z][A-Za-z0-9+.-]*:\/\//.test(s))
|
|
37
|
+
return null;
|
|
30
38
|
if (!looksLikeFilePath(s) && !isImageName(s))
|
|
31
39
|
return null;
|
|
32
40
|
const candidates = path.isAbsolute(s)
|
|
@@ -62,12 +70,12 @@ async function isInside(workdir, target) {
|
|
|
62
70
|
const rel = path.relative(root, real);
|
|
63
71
|
return !rel.startsWith('..') && !path.isAbsolute(rel);
|
|
64
72
|
}
|
|
65
|
-
// Per-file and total caps for `@path` inlining
|
|
73
|
+
// Per-file and total caps for `@path` inlining . A reference should SAVE
|
|
66
74
|
// round-trips, not flood the context: a huge file is truncated with a note
|
|
67
75
|
// telling the agent to read the rest itself.
|
|
68
76
|
export const AT_REF_FILE_CAP = 60 * 1024;
|
|
69
77
|
export const AT_REF_TOTAL_CAP = 200 * 1024;
|
|
70
|
-
// Inline `@path` references found in a task text
|
|
78
|
+
// Inline `@path` references found in a task text . Returns the augmented
|
|
71
79
|
// text plus the list of files actually inlined (for the operator notice).
|
|
72
80
|
// Unknown/unreadable references are left in place untouched -- they may be
|
|
73
81
|
// part of the prose; we never fail the task over a missing file.
|
|
@@ -93,8 +101,17 @@ export async function inlineAtRefs(workdir, text) {
|
|
|
93
101
|
}
|
|
94
102
|
let body = raw;
|
|
95
103
|
let note = '';
|
|
96
|
-
|
|
97
|
-
|
|
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;
|
|
98
115
|
// Never end the inlined block on a lone HIGH surrogate: the cut is in
|
|
99
116
|
// UTF-16 units, so an emoji / astral CJK char on the boundary would
|
|
100
117
|
// reach the model as a broken code point (same rule as
|
|
@@ -103,7 +120,14 @@ export async function inlineAtRefs(workdir, text) {
|
|
|
103
120
|
if (last >= 0xd800 && last <= 0xdbff)
|
|
104
121
|
cut--;
|
|
105
122
|
body = body.slice(0, cut);
|
|
106
|
-
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
|
+
')';
|
|
107
131
|
}
|
|
108
132
|
total += body.length;
|
|
109
133
|
inlined.push(path.relative(workdir, file) || file);
|
package/dist/attachments.js
CHANGED
|
@@ -186,6 +186,15 @@ export function looksLikeFilePath(text) {
|
|
|
186
186
|
return false;
|
|
187
187
|
if (/[\r\n]/.test(s))
|
|
188
188
|
return false;
|
|
189
|
+
// A URL is not a file path. It contains `/` and ends in a short extension,
|
|
190
|
+
// so it used to pass, and resolveAttachPath then resolved it RELATIVELY
|
|
191
|
+
// (`https://…` -> `https:/…`): a project that happened to contain such a
|
|
192
|
+
// directory silently attached the URL as a local file instead of keeping
|
|
193
|
+
// the text. Any `scheme://` head is rejected here — INCLUDING one that sits
|
|
194
|
+
// after prose words (`see https://x/a.png`), since the whole trimmed text is
|
|
195
|
+
// handed to this check.
|
|
196
|
+
if (/(?:^|\s)[A-Za-z][A-Za-z0-9+.-]*:\/\//.test(s))
|
|
197
|
+
return false;
|
|
189
198
|
// A bare file name with an image/known extension.
|
|
190
199
|
if (looksLikeFileName(s))
|
|
191
200
|
return true;
|
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
|
|
@@ -27,7 +27,14 @@ export function parseHistoryMessages(messages) {
|
|
|
27
27
|
const list = [];
|
|
28
28
|
let usage = null;
|
|
29
29
|
for (const raw of messages) {
|
|
30
|
-
|
|
30
|
+
// A token counter is a FINITE NON-NEGATIVE number. A negative value is a
|
|
31
|
+
// nonsense payload; it used to become browser._lastTokenUsage as-is, so
|
|
32
|
+
// the context badge vanished (tokenStatusLevel rejects a negative count)
|
|
33
|
+
// and the auto-compact percentage went negative and never fired.
|
|
34
|
+
if (raw &&
|
|
35
|
+
typeof raw.accumulated_token_usage === 'number' &&
|
|
36
|
+
Number.isFinite(raw.accumulated_token_usage) &&
|
|
37
|
+
raw.accumulated_token_usage >= 0) {
|
|
31
38
|
usage = raw.accumulated_token_usage;
|
|
32
39
|
}
|
|
33
40
|
// Roles are matched case-insensitively, and a turn that is neither the
|
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
|