zames_pro 2.82.136 → 2.82.137
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 +6 -0
- package/dist/agent-loop.js +9 -9
- package/dist/changelog.js +1 -1
- package/dist/commands.js +1 -1
- package/dist/compact.js +1 -1
- package/dist/config.js +1 -1
- package/dist/index.js +8 -8
- package/dist/input.js +3 -3
- package/dist/run-task.js +7 -7
- package/dist/statusline.js +1 -1
- package/dist/subagent.js +1 -1
- package/dist/tools.js +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [2.82.137] - 2026-10-24
|
|
11
|
+
|
|
12
|
+
### Changed
|
|
13
|
+
|
|
14
|
+
- docs: drop backlog-id references from source comments
|
|
15
|
+
|
|
10
16
|
## [2.82.136] - 2026-10-24
|
|
11
17
|
|
|
12
18
|
### Fixed
|
package/dist/agent-loop.js
CHANGED
|
@@ -14,7 +14,7 @@ export async function runAgentLoop({ browser, tools, task, workdir, maxIteration
|
|
|
14
14
|
// `undefined` means "read .zames/hooks.json"; an explicit null disables
|
|
15
15
|
// hooks entirely.
|
|
16
16
|
const hookConfig = hooks === undefined ? loadHooks(workdir) : (hooks ?? {});
|
|
17
|
-
// Same for the approval policy
|
|
17
|
+
// Same for the approval policy: read `.zames/permissions.json` once.
|
|
18
18
|
const permissionPolicy = permissions === undefined ? loadPermissions(workdir) : permissions;
|
|
19
19
|
// UI callbacks must NEVER break the agent loop. A rendering error (a huge
|
|
20
20
|
// tool result, a broken markdown frame, a closed terminal) used to throw
|
|
@@ -81,7 +81,7 @@ export async function runAgentLoop({ browser, tools, task, workdir, maxIteration
|
|
|
81
81
|
if (freshChat) {
|
|
82
82
|
await browser.newChat();
|
|
83
83
|
transcript?.log('new_chat');
|
|
84
|
-
// SessionStart hook
|
|
84
|
+
// SessionStart hook: a fresh chat is the start of a session, so a
|
|
85
85
|
// hook can inject context or set up state. Best-effort, output is logged.
|
|
86
86
|
try {
|
|
87
87
|
const out = await runLifecycleHooks(hookConfig, 'SessionStart', workdir);
|
|
@@ -118,7 +118,7 @@ export async function runAgentLoop({ browser, tools, task, workdir, maxIteration
|
|
|
118
118
|
let context;
|
|
119
119
|
try {
|
|
120
120
|
// Pass the task text so nested AGENTS.md/MEMORY.md for the directories
|
|
121
|
-
// this task actually touches are pulled in (
|
|
121
|
+
// this task actually touches are pulled in (path-scoped rules).
|
|
122
122
|
context = await loadProjectContext(workdir, [task]);
|
|
123
123
|
}
|
|
124
124
|
catch {
|
|
@@ -280,7 +280,7 @@ export async function runAgentLoop({ browser, tools, task, workdir, maxIteration
|
|
|
280
280
|
let lastAutoCompactTokens = -1;
|
|
281
281
|
// Set when an auto-compact returned the SAME chat id it started in — i.e.
|
|
282
282
|
// the "fresh chat" never opened and the compaction did nothing. Without this
|
|
283
|
-
// guard a broken newChat()
|
|
283
|
+
// guard a broken newChat() made the loop compact on EVERY tool call
|
|
284
284
|
// while the context kept growing. Defense in depth: the root cause is fixed,
|
|
285
285
|
// but a future regression must not turn into an endless "compacting" loop.
|
|
286
286
|
let autoCompactDisabled = false;
|
|
@@ -314,7 +314,7 @@ export async function runAgentLoop({ browser, tools, task, workdir, maxIteration
|
|
|
314
314
|
// 300s rate-limit wait or the finish loop) while the next iteration
|
|
315
315
|
// started a SECOND ask() against the same page — two sends / two Continue
|
|
316
316
|
// clicks.
|
|
317
|
-
// UserPromptSubmit hook
|
|
317
|
+
// UserPromptSubmit hook: runs right before the prompt is sent. Its
|
|
318
318
|
// stdout is appended to the outgoing message as extra context, mirroring
|
|
319
319
|
// Claude Code. Best-effort — a hook failure never blocks the send.
|
|
320
320
|
try {
|
|
@@ -787,7 +787,7 @@ export async function runAgentLoop({ browser, tools, task, workdir, maxIteration
|
|
|
787
787
|
'repeat the identical call.';
|
|
788
788
|
continue;
|
|
789
789
|
}
|
|
790
|
-
//
|
|
790
|
+
// Several READ-ONLY calls in one batch are independent, so run them
|
|
791
791
|
// concurrently instead of one-by-one (the model often emits 4-6 Reads in a
|
|
792
792
|
// single answer and each awaited round-trip added latency). The fast path
|
|
793
793
|
// is deliberately NARROW: it is taken only when EVERY call is a known
|
|
@@ -1016,7 +1016,7 @@ export async function runAgentLoop({ browser, tools, task, workdir, maxIteration
|
|
|
1016
1016
|
results.push({ tool: call.tool, result: blocked });
|
|
1017
1017
|
continue;
|
|
1018
1018
|
}
|
|
1019
|
-
// Approval policy
|
|
1019
|
+
// Approval policy: a `deny` rule blocks the call (like a PreToolUse
|
|
1020
1020
|
// denial); an `ask` rule prompts the operator. Hooks stay authoritative
|
|
1021
1021
|
// for programmatic guards — this is the human-in-the-loop layer.
|
|
1022
1022
|
const decision = decidePermission(permissionPolicy, call.tool, call.args);
|
|
@@ -1065,7 +1065,7 @@ export async function runAgentLoop({ browser, tools, task, workdir, maxIteration
|
|
|
1065
1065
|
const poll = setInterval(syncToolAbort, 100);
|
|
1066
1066
|
if (typeof poll.unref === 'function')
|
|
1067
1067
|
poll.unref();
|
|
1068
|
-
// Time the tool
|
|
1068
|
+
// Time the tool: the transcript carries durationMs so /cost can
|
|
1069
1069
|
// show where the time goes (frequent Read→Edit cycles vs slow Bash).
|
|
1070
1070
|
const toolStart = Date.now();
|
|
1071
1071
|
try {
|
|
@@ -1089,7 +1089,7 @@ export async function runAgentLoop({ browser, tools, task, workdir, maxIteration
|
|
|
1089
1089
|
[PostToolUse hook]
|
|
1090
1090
|
${post}`;
|
|
1091
1091
|
}
|
|
1092
|
-
//
|
|
1092
|
+
// After a file-mutating tool, run the project's own check and
|
|
1093
1093
|
// append its summary, so a type error reaches the model immediately
|
|
1094
1094
|
// instead of costing a whole round-trip. Best-effort and capped.
|
|
1095
1095
|
if (shouldRunDiagnostics(diagnostics, call.tool)) {
|
package/dist/changelog.js
CHANGED
|
@@ -80,7 +80,7 @@ export function renderChangelogDraft(groups) {
|
|
|
80
80
|
}
|
|
81
81
|
/**
|
|
82
82
|
* Replace the body between `## [Unreleased]` and the next `## [` heading with
|
|
83
|
-
* a freshly drafted body
|
|
83
|
+
* a freshly drafted body. PURE so a test can pin the exact behavior.
|
|
84
84
|
*
|
|
85
85
|
* When `body` is empty the existing Unreleased section is CLEARED to just the
|
|
86
86
|
* heading (no stray blank content). A changelog without an Unreleased heading
|
package/dist/commands.js
CHANGED
|
@@ -238,7 +238,7 @@ export function renderCost(stats, transcriptFile, tokenUsage = null, t = transla
|
|
|
238
238
|
for (const [name, n] of top)
|
|
239
239
|
lines.push(' ' + nameLine(name) + ': ' + n);
|
|
240
240
|
}
|
|
241
|
-
//
|
|
241
|
+
// Where the time went. Sort by total ms, show the top tools with the
|
|
242
242
|
// count and a human duration, so Read→Edit cycles and slow Bash calls are
|
|
243
243
|
// visible at a glance.
|
|
244
244
|
const byTime = Object.entries(stats.toolTime || {})
|
package/dist/compact.js
CHANGED
|
@@ -43,7 +43,7 @@ export async function performCompact(opts) {
|
|
|
43
43
|
try {
|
|
44
44
|
if (!quiet)
|
|
45
45
|
log(t('compact.start'));
|
|
46
|
-
// PreCompact hook
|
|
46
|
+
// PreCompact hook: runs BEFORE the chat is summarized/rewritten, so
|
|
47
47
|
// a hook can persist state or notify. Best-effort.
|
|
48
48
|
try {
|
|
49
49
|
const out = await runLifecycleHooks(loadHooks(workdir), 'PreCompact', workdir, { chatId: currentChatId });
|
package/dist/config.js
CHANGED
|
@@ -135,7 +135,7 @@ export const DEFAULTS = {
|
|
|
135
135
|
contextLimit: 1_000_000,
|
|
136
136
|
// 0 = auto: terminal width, capped at 100 columns (the historical width).
|
|
137
137
|
answerWidth: 0,
|
|
138
|
-
//
|
|
138
|
+
// statusLine hook. Off by default; edit config.json to set a command.
|
|
139
139
|
statusLineCommand: '',
|
|
140
140
|
statusLineIntervalMs: 10_000,
|
|
141
141
|
// Use the Ink/React TUI for the input area (the rich editor). Set to false
|
package/dist/index.js
CHANGED
|
@@ -257,7 +257,7 @@ const RELOADABLE = [
|
|
|
257
257
|
'config',
|
|
258
258
|
'fsutil',
|
|
259
259
|
'backlog',
|
|
260
|
-
//
|
|
260
|
+
// Modules index.ts now calls through the mod bag: without this a
|
|
261
261
|
// /reload silently kept the OLD commands/run-task/attach-refs until a restart.
|
|
262
262
|
// 'input/layout' is NOT listed: its only live consumers are input.ts (the
|
|
263
263
|
// long-lived LineEditor, itself not reloadable) and spinner.ts, which already
|
|
@@ -594,7 +594,7 @@ async function refreshDynamicCommands(workdir) {
|
|
|
594
594
|
}
|
|
595
595
|
const cmds = await loadCommands(workdir);
|
|
596
596
|
for (const c of cmds) {
|
|
597
|
-
//
|
|
597
|
+
// Carry the declared argument hint as a separate field so the hint is
|
|
598
598
|
// SHOWN in the suggest list but never inserted into the input line.
|
|
599
599
|
out.push({
|
|
600
600
|
name: '/' + c.name,
|
|
@@ -619,7 +619,7 @@ async function expandSlashTarget(workdir, name, rest) {
|
|
|
619
619
|
const commands = await loadCommands(workdir);
|
|
620
620
|
const cmd = commands.find((c) => c.name.toLowerCase() === name.toLowerCase());
|
|
621
621
|
if (cmd) {
|
|
622
|
-
//
|
|
622
|
+
// Refuse to run when declared positional arguments are missing.
|
|
623
623
|
const missing = mod.commands.missingCommandArgs(cmd.arguments, rest);
|
|
624
624
|
if (missing.length)
|
|
625
625
|
return { missing };
|
|
@@ -1410,7 +1410,7 @@ async function main() {
|
|
|
1410
1410
|
let reviewMode = null;
|
|
1411
1411
|
process.on('SIGINT', async () => {
|
|
1412
1412
|
running = false;
|
|
1413
|
-
// Kill any background processes
|
|
1413
|
+
// Kill any background processes so no dev-server outlives the agent.
|
|
1414
1414
|
killAllBackground();
|
|
1415
1415
|
await browser.close().catch(() => { });
|
|
1416
1416
|
// Close the lazy headless browser from web.js, otherwise it would stay
|
|
@@ -1468,7 +1468,7 @@ async function main() {
|
|
|
1468
1468
|
// swap. Assigned where the editor is built (see the login wiring below);
|
|
1469
1469
|
// a no-op until then so /provider before setup is harmless.
|
|
1470
1470
|
let wireLoginCallbacks = () => { };
|
|
1471
|
-
//
|
|
1471
|
+
// statusLine hook timer (cleared on exit).
|
|
1472
1472
|
let statusLineTimer = null;
|
|
1473
1473
|
let waiter = null;
|
|
1474
1474
|
const takeInput = () => {
|
|
@@ -1619,7 +1619,7 @@ async function main() {
|
|
|
1619
1619
|
};
|
|
1620
1620
|
};
|
|
1621
1621
|
wireLoginCallbacks(browser);
|
|
1622
|
-
//
|
|
1622
|
+
// statusLine hook: run the configured command on its own timer (never
|
|
1623
1623
|
// per-render — a spawn would block typing) and show its first stdout line
|
|
1624
1624
|
// in the status line. Off when ui.statusLineCommand is empty.
|
|
1625
1625
|
if (config.ui.statusLineCommand) {
|
|
@@ -4065,7 +4065,7 @@ async function main() {
|
|
|
4065
4065
|
}
|
|
4066
4066
|
}
|
|
4067
4067
|
}
|
|
4068
|
-
//
|
|
4068
|
+
// A custom command with mandatory `arguments:` refuses to run until the
|
|
4069
4069
|
// operator supplies them (by position).
|
|
4070
4070
|
if (missingArgs) {
|
|
4071
4071
|
console.error(theme.error(t('msg.missing_args', { v: missingArgs.join(', ') })));
|
|
@@ -4081,7 +4081,7 @@ async function main() {
|
|
|
4081
4081
|
: expandedTask !== null
|
|
4082
4082
|
? expandedTask
|
|
4083
4083
|
: trimmed;
|
|
4084
|
-
//
|
|
4084
|
+
// Inline any `@path` references into the task so the agent does not
|
|
4085
4085
|
// spend a round-trip reading a file the operator already pointed at. Only
|
|
4086
4086
|
// existing files are inlined; a bare `@name` in prose is left untouched.
|
|
4087
4087
|
let finalTaskText = taskText;
|
package/dist/input.js
CHANGED
|
@@ -173,7 +173,7 @@ export class LineEditor {
|
|
|
173
173
|
// A callback the editor calls before every render to read the agent's
|
|
174
174
|
// current task-list summary ("tasks: 2/5"), empty when there is no list.
|
|
175
175
|
onTasksQuery;
|
|
176
|
-
// Extra status text produced by an external command (
|
|
176
|
+
// Extra status text produced by an external command (the statusLine hook).
|
|
177
177
|
// Set via setStatusLine(); shown before the queue/tasks badges. Kept as a
|
|
178
178
|
// plain field because the CALLER runs the command on its own timer (a
|
|
179
179
|
// per-render spawn would block typing).
|
|
@@ -361,7 +361,7 @@ export class LineEditor {
|
|
|
361
361
|
return '';
|
|
362
362
|
}
|
|
363
363
|
}
|
|
364
|
-
// The statusLine hook text
|
|
364
|
+
// The statusLine hook text, shown before the queue/tasks badges.
|
|
365
365
|
// A trailing space separates it from whatever follows; empty hides it.
|
|
366
366
|
_statusLineBadge() {
|
|
367
367
|
return this.statusLine ? theme.system(this.statusLine) + ' ' : '';
|
|
@@ -605,7 +605,7 @@ export class LineEditor {
|
|
|
605
605
|
}
|
|
606
606
|
// Update the context window size (from config.ui.contextLimit). The next
|
|
607
607
|
// render recomputes the percentage and its color with the new limit.
|
|
608
|
-
// Set the statusLine hook text
|
|
608
|
+
// Set the statusLine hook text. The caller runs the command on its
|
|
609
609
|
// own timer; this only stores + repaints. An empty string hides the badge.
|
|
610
610
|
setStatusLine(text) {
|
|
611
611
|
const t = String(text || '').trim();
|
package/dist/run-task.js
CHANGED
|
@@ -5,7 +5,7 @@ import { formatCompactTokens, pasteReplacement, expandPastes } from './input.js'
|
|
|
5
5
|
import { DEFAULT_LOCALE } from './i18n.js';
|
|
6
6
|
import { providerAskDeadlineMs } from './config.js';
|
|
7
7
|
// Ask the operator to approve a tool call flagged by an `ask` permission rule
|
|
8
|
-
//
|
|
8
|
+
// While the LineEditor owns the terminal it must be paused first, or the
|
|
9
9
|
// confirmation prompt and the input line fight for the same keys. A non-TTY run
|
|
10
10
|
// has no way to answer, so it DENIES (never silently allows a guarded call).
|
|
11
11
|
export async function askOperatorConfirm(editor, question, t,
|
|
@@ -332,7 +332,7 @@ export async function runTask(deps, browser, tools, taskText, workdir, opts, att
|
|
|
332
332
|
// Set when the loop ends without a real answer (iteration limit / watchdog)
|
|
333
333
|
// so the one-shot mode can exit non-zero. See N5.
|
|
334
334
|
let failure = null;
|
|
335
|
-
//
|
|
335
|
+
// The machine-readable reason for the last task's outcome.
|
|
336
336
|
let outcomeKind = 'ok';
|
|
337
337
|
// How many auto-continue turns a completion goal has already spent.
|
|
338
338
|
let goalTurns = 0;
|
|
@@ -389,7 +389,7 @@ export async function runTask(deps, browser, tools, taskText, workdir, opts, att
|
|
|
389
389
|
},
|
|
390
390
|
onWarning: (msg) => ui.warning(msg),
|
|
391
391
|
onAskPermission: async (info) => {
|
|
392
|
-
//
|
|
392
|
+
// A rule with action "ask". Show the reason and wait for the
|
|
393
393
|
// operator. In non-TTY this denies.
|
|
394
394
|
ui.warning(t('perm.ask', { tool: info.tool, reason: info.reason }));
|
|
395
395
|
const ok = await askOperatorConfirm(editor || null, t('perm.confirm'), t, locale);
|
|
@@ -440,7 +440,7 @@ export async function runTask(deps, browser, tools, taskText, workdir, opts, att
|
|
|
440
440
|
}
|
|
441
441
|
}
|
|
442
442
|
: onAskUser,
|
|
443
|
-
//
|
|
443
|
+
// The check command appended to a tool result after an edit
|
|
444
444
|
// (off by default; config.diagnostics).
|
|
445
445
|
diagnostics: deps.config.diagnostics,
|
|
446
446
|
});
|
|
@@ -452,7 +452,7 @@ export async function runTask(deps, browser, tools, taskText, workdir, opts, att
|
|
|
452
452
|
ui.warning(outcome);
|
|
453
453
|
transcript?.log('agent_no_answer', { outcome });
|
|
454
454
|
failure = outcome;
|
|
455
|
-
//
|
|
455
|
+
// A machine-readable reason so `--output-format jsonl` consumers
|
|
456
456
|
// (CI) can tell a real error from an exhausted limit / watchdog.
|
|
457
457
|
outcomeKind = outcome.startsWith('Iteration limit reached')
|
|
458
458
|
? 'iteration_limit'
|
|
@@ -570,7 +570,7 @@ export async function runTask(deps, browser, tools, taskText, workdir, opts, att
|
|
|
570
570
|
sendSystemPrompt: false,
|
|
571
571
|
};
|
|
572
572
|
}
|
|
573
|
-
// Stop hook
|
|
573
|
+
// Stop hook: the whole task (including drained queue messages) is
|
|
574
574
|
// done. A cleanup/notification hook runs here. Best-effort.
|
|
575
575
|
try {
|
|
576
576
|
// LOAD the config: `undefined` here made every Stop hook a no-op — the
|
|
@@ -584,7 +584,7 @@ export async function runTask(deps, browser, tools, taskText, workdir, opts, att
|
|
|
584
584
|
ui.warning(out);
|
|
585
585
|
}
|
|
586
586
|
catch { }
|
|
587
|
-
//
|
|
587
|
+
// A single terminal event carrying the reason, so a jsonl consumer
|
|
588
588
|
// does not have to guess from the exit code alone.
|
|
589
589
|
transcript?.log('task_result', {
|
|
590
590
|
ok: !failure,
|
package/dist/statusline.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { spawn } from 'node:child_process';
|
|
2
|
-
//
|
|
2
|
+
// statusLine hook. When `ui.statusLineCommand` is set, zames runs it on a
|
|
3
3
|
// timer with a JSON status object on stdin and shows the FIRST line of its
|
|
4
4
|
// stdout in the status line (like Claude Code). The command is deliberately
|
|
5
5
|
// run OUT of the render path: a per-render spawn would block typing, so the
|
package/dist/subagent.js
CHANGED
|
@@ -178,7 +178,7 @@ export function createSubagentRunner(opts) {
|
|
|
178
178
|
browser.onSendState = savedHooks.onSendState;
|
|
179
179
|
browser.onNotice = savedHooks.onNotice;
|
|
180
180
|
}
|
|
181
|
-
// SubagentStop hook
|
|
181
|
+
// SubagentStop hook: fires after the nested loop finishes, so a hook
|
|
182
182
|
// can clean up or notify. Best-effort; its stdout is appended to the report.
|
|
183
183
|
let hookOut = '';
|
|
184
184
|
try {
|
package/dist/tools.js
CHANGED
|
@@ -104,7 +104,7 @@ export function createTools(workdir, { undo, todos, readOnly = false, subagents
|
|
|
104
104
|
},
|
|
105
105
|
fn: async ({ path: p, offset, limit, numbered }) => {
|
|
106
106
|
const file = safe(req(p, 'path'));
|
|
107
|
-
// Binary guard
|
|
107
|
+
// Binary guard: reading an image/archive as utf-8 produced
|
|
108
108
|
// mojibake the model tried to reason about. Detect a binary buffer
|
|
109
109
|
// BEFORE decoding and answer with useful metadata instead.
|
|
110
110
|
// A read FAILURE (a missing file, a directory, EACCES) is answered in
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "zames_pro",
|
|
3
|
-
"version": "2.82.
|
|
3
|
+
"version": "2.82.137",
|
|
4
4
|
"description": "Terminal coding agent that drives a real browser to chat with DeepSeek, Qwen and other web LLMs — no API key required. Reads and edits files, runs commands, commits to git, like Claude Code / Codex CLI.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|