zames_pro 2.82.137 → 2.82.138
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 +70 -0
- package/dist/agent-loop.js +3 -6
- package/dist/answer-parse.js +10 -16
- package/dist/attach-refs.js +3 -3
- package/dist/attachments.js +7 -8
- package/dist/backlog.js +2 -5
- package/dist/banner.js +4 -5
- package/dist/browser-chats.js +4 -4
- package/dist/browser-dom.js +16 -15
- package/dist/browser-login.js +9 -5
- package/dist/browser-pure.js +5 -5
- package/dist/browser.js +10 -20
- package/dist/changelog.js +14 -20
- package/dist/checkpoint.js +6 -10
- package/dist/cli-args.js +4 -6
- package/dist/code-blocks.js +3 -6
- package/dist/commands.js +5 -9
- package/dist/config-command.js +6 -4
- package/dist/config-commands.js +2 -3
- package/dist/config-live.js +7 -13
- package/dist/config-menu.js +5 -4
- package/dist/config.js +5 -8
- package/dist/deepseek-ui.js +7 -7
- package/dist/diagnostics.js +5 -7
- package/dist/diff.js +8 -10
- package/dist/extraTools.js +3 -3
- package/dist/fsutil.js +0 -4
- package/dist/gitTools.js +5 -4
- package/dist/glm-browser.js +2 -10
- package/dist/glm-chats.js +0 -1
- package/dist/glm-net-capture.js +1 -1
- package/dist/glm-ui.js +2 -2
- package/dist/goal.js +1 -4
- package/dist/i18n/common.js +2 -2
- package/dist/i18n.js +1 -2
- package/dist/index.js +0 -11
- package/dist/input/suggest.js +4 -7
- package/dist/input.js +3 -8
- package/dist/markdown.js +0 -1
- package/dist/mcp.js +2 -5
- package/dist/net-capture.js +1 -1
- package/dist/path-token.js +7 -14
- package/dist/prompt.js +4 -3
- package/dist/qwen-browser.js +1 -8
- package/dist/qwen-chats.js +0 -1
- package/dist/qwen-net-capture.js +4 -7
- package/dist/qwen-ui.js +0 -3
- package/dist/run-task.js +4 -4
- package/dist/self-review.js +0 -5
- package/dist/send-runtime.js +6 -10
- package/dist/send-telemetry.js +5 -7
- package/dist/send-throttle.js +4 -5
- package/dist/sessions.js +6 -7
- package/dist/spinner.js +3 -4
- package/dist/statusline.js +5 -9
- package/dist/system-prompt.js +1 -1
- package/dist/tui/widgets.js +0 -1
- package/package.json +1 -1
package/dist/input.js
CHANGED
|
@@ -96,7 +96,7 @@ export class LineEditor {
|
|
|
96
96
|
// is stored so it can be removed in dispose().
|
|
97
97
|
_onResize;
|
|
98
98
|
_resizeTimer;
|
|
99
|
-
// ESC disambiguation
|
|
99
|
+
// ESC disambiguation: a read may end on a bare ESC that is really the
|
|
100
100
|
// head of a control sequence split across two reads. We hold it briefly and
|
|
101
101
|
// fire onEscape only if no tail arrives.
|
|
102
102
|
_escPending;
|
|
@@ -644,7 +644,6 @@ export class LineEditor {
|
|
|
644
644
|
this.pastes = [];
|
|
645
645
|
this._render();
|
|
646
646
|
}
|
|
647
|
-
// ---------- rendering ----------
|
|
648
647
|
_eraseBlock() {
|
|
649
648
|
if (!this.rendered)
|
|
650
649
|
return;
|
|
@@ -936,7 +935,6 @@ export class LineEditor {
|
|
|
936
935
|
process.stdout.write(String(text) + NL);
|
|
937
936
|
this._writeBlock();
|
|
938
937
|
}
|
|
939
|
-
// ---------- spinner-compatible interface ----------
|
|
940
938
|
setStatus(text) {
|
|
941
939
|
this.statusText = text || '';
|
|
942
940
|
this._render();
|
|
@@ -1124,7 +1122,6 @@ export class LineEditor {
|
|
|
1124
1122
|
const wrapped = wrapToWidth('⚠ ' + msg, maxW);
|
|
1125
1123
|
this.printAbove(NL + theme.warn(wrapped));
|
|
1126
1124
|
}
|
|
1127
|
-
// ---------- input ----------
|
|
1128
1125
|
_submit() {
|
|
1129
1126
|
if (this.locked) {
|
|
1130
1127
|
this._render();
|
|
@@ -1367,7 +1364,7 @@ export class LineEditor {
|
|
|
1367
1364
|
}
|
|
1368
1365
|
// Bare ESC: wait a moment for a possible control-sequence tail before firing
|
|
1369
1366
|
// onEscape. Without this a sequence split across two reads (ESC, then "[A")
|
|
1370
|
-
// looked like a lone Escape and aborted the current generation
|
|
1367
|
+
// looked like a lone Escape and aborted the current generation.
|
|
1371
1368
|
_scheduleEscape() {
|
|
1372
1369
|
this._escPending = true;
|
|
1373
1370
|
if (this._escTimer)
|
|
@@ -1460,7 +1457,6 @@ export class LineEditor {
|
|
|
1460
1457
|
chars.splice(this.cursor, i - this.cursor);
|
|
1461
1458
|
this.buf = chars.join('');
|
|
1462
1459
|
}
|
|
1463
|
-
// ---------- history ----------
|
|
1464
1460
|
_historyUp() {
|
|
1465
1461
|
if (!this.history.length)
|
|
1466
1462
|
return;
|
|
@@ -1485,7 +1481,6 @@ export class LineEditor {
|
|
|
1485
1481
|
}
|
|
1486
1482
|
this.cursor = Array.from(this.buf).length;
|
|
1487
1483
|
}
|
|
1488
|
-
// ---------- reverse-search (Ctrl+R) ----------
|
|
1489
1484
|
// Start an incremental reverse search, keeping the current buffer aside so
|
|
1490
1485
|
// Esc restores it (bash behavior). An empty history leaves the editor
|
|
1491
1486
|
// untouched.
|
|
@@ -1596,7 +1591,7 @@ export class LineEditor {
|
|
|
1596
1591
|
// A previous read ended on a bare ESC. That is ambiguous: the Escape key
|
|
1597
1592
|
// or the head of a control sequence split across reads (arrows, Ctrl+Del).
|
|
1598
1593
|
// Reattach the ESC and parse the whole sequence, so a split arrow does not
|
|
1599
|
-
// abort the generation
|
|
1594
|
+
// abort the generation.
|
|
1600
1595
|
if (this._escPending) {
|
|
1601
1596
|
this._escPending = false;
|
|
1602
1597
|
if (this._escTimer) {
|
package/dist/markdown.js
CHANGED
package/dist/mcp.js
CHANGED
|
@@ -477,11 +477,8 @@ export async function createMcpPool(opts) {
|
|
|
477
477
|
}
|
|
478
478
|
}
|
|
479
479
|
// Distinct servers can produce the SAME qualified name (server 'a' + tool
|
|
480
|
-
// 'b__c' vs server 'a__b' + tool 'c')
|
|
481
|
-
//
|
|
482
|
-
// tool silently unreachable (the model calls "the right name", a DIFFERENT
|
|
483
|
-
// tool runs). Rename the later one with a numeric suffix so every name is
|
|
484
|
-
// unique.
|
|
480
|
+
// 'b__c' vs server 'a__b' + tool 'c'); dedupeToolNames below explains why
|
|
481
|
+
// that has to be fixed rather than left to tools.find().
|
|
485
482
|
dedupeToolNames(tools);
|
|
486
483
|
let closed = false;
|
|
487
484
|
return {
|
package/dist/net-capture.js
CHANGED
|
@@ -259,7 +259,7 @@ export function isFinishedWithAnswer(body) {
|
|
|
259
259
|
return false;
|
|
260
260
|
// A truncated RESPONSE head (a lone `{`) is NOT a complete answer: the
|
|
261
261
|
// finish loop would return it as the model's text and the tool-call parser
|
|
262
|
-
// would fail on it. Require real content (see
|
|
262
|
+
// would fail on it. Require real content (see responseTextLength).
|
|
263
263
|
return responseContentLength(b) >= MIN_REAL_ANSWER_CHARS;
|
|
264
264
|
}
|
|
265
265
|
// The CONTEXT size (in tokens) DeepSeek reports for the current answer.
|
package/dist/path-token.js
CHANGED
|
@@ -118,15 +118,11 @@ export function extractAtFileRefs(text) {
|
|
|
118
118
|
}
|
|
119
119
|
let j = i + 1;
|
|
120
120
|
let tok = '';
|
|
121
|
-
// The token is rejected WHOLE when it contains an at-sign that is NOT a
|
|
122
|
-
// list separator — `@Component` / `user@host` are a decorator and an
|
|
123
|
-
// email. Trimming the prefix at that at-sign would otherwise inline a
|
|
124
|
-
// bogus path.
|
|
125
|
-
let hadInnerAt = false;
|
|
126
121
|
// A token that contains an at-sign (`@Component`, `user@host`) is a
|
|
127
|
-
// decorator
|
|
128
|
-
//
|
|
129
|
-
// BEFORE it to the inliner
|
|
122
|
+
// decorator or an email, NOT a file reference, and the WHOLE token is
|
|
123
|
+
// rejected: the scan used to stop at that at-sign and hand the part
|
|
124
|
+
// BEFORE it to the inliner, which inlined a bogus path.
|
|
125
|
+
let hadInnerAt = false;
|
|
130
126
|
const isRef = (t) => t.length > 0 && !t.includes('@');
|
|
131
127
|
while (j < n && !isRefEnd(chars[j])) {
|
|
132
128
|
// A COMMA directly followed by another `@` starts the NEXT reference:
|
|
@@ -154,12 +150,9 @@ export function extractAtFileRefs(text) {
|
|
|
154
150
|
seen.add(cleaned);
|
|
155
151
|
out.push(cleaned);
|
|
156
152
|
}
|
|
157
|
-
// The
|
|
158
|
-
//
|
|
159
|
-
//
|
|
160
|
-
// The scan stopped ON a separator that split the token (`,`, `;` or a
|
|
161
|
-
// second at-sign): resume AT it so the next part is scanned as its own
|
|
162
|
-
// reference. Continuing past it dropped the second file of a list.
|
|
153
|
+
// The scan may have stopped ON a separator that split the token (`,`, `;`
|
|
154
|
+
// or a second at-sign): resume AT it so the next part is scanned as its
|
|
155
|
+
// own reference. Continuing past it dropped the second file of a list.
|
|
163
156
|
const sep = j < n ? chars[j] : '';
|
|
164
157
|
if (j > i + 1 && (sep === ',' || sep === ';' || sep === '@'))
|
|
165
158
|
i = j;
|
package/dist/prompt.js
CHANGED
|
@@ -31,7 +31,8 @@ export async function promptOnce(question) {
|
|
|
31
31
|
const wasRaw = stdin.isRaw;
|
|
32
32
|
stdin.setRawMode(true);
|
|
33
33
|
stdin.resume();
|
|
34
|
-
//
|
|
34
|
+
// Bracketed paste is enabled/disabled in pairs, so the terminal is left in
|
|
35
|
+
// normal mode however the prompt exits.
|
|
35
36
|
stdout.write('\x1b[?2004h');
|
|
36
37
|
stdout.write(question);
|
|
37
38
|
let line = '';
|
|
@@ -40,11 +41,11 @@ export async function promptOnce(question) {
|
|
|
40
41
|
const PASTE_START = '\x1b[200~';
|
|
41
42
|
const PASTE_END = '\x1b[201~';
|
|
42
43
|
const redraw = () => {
|
|
43
|
-
//
|
|
44
|
+
// Redraw in place: CR + erase-to-end, then the prompt and the line again.
|
|
44
45
|
stdout.write(String.fromCharCode(13));
|
|
45
46
|
stdout.write('\x1b[K');
|
|
46
47
|
stdout.write(question + line);
|
|
47
|
-
//
|
|
48
|
+
// Step back to the cursor, measured in UTF-16 units.
|
|
48
49
|
const back = line.length - cursor;
|
|
49
50
|
if (back > 0)
|
|
50
51
|
stdout.write('\x1b[' + back + 'D');
|
package/dist/qwen-browser.js
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
// and the chat-id scheme. DeepSeekBrowser is already large; folding a second
|
|
7
7
|
// site into it would make both harder to audit. The shared surface is the
|
|
8
8
|
// ChatProvider interface (types.ts); the agent loop only needs BrowserLike and
|
|
9
|
-
// never sees
|
|
9
|
+
// never sees a concrete class.
|
|
10
10
|
//
|
|
11
11
|
// Verified against a live session (headless Chromium, guest + logged in):
|
|
12
12
|
// input -> textarea.message-input-textarea
|
|
@@ -233,7 +233,6 @@ export class QwenBrowser {
|
|
|
233
233
|
sendIntervalMs() {
|
|
234
234
|
return this.minSendIntervalMs;
|
|
235
235
|
}
|
|
236
|
-
// ---------- lifecycle ----------
|
|
237
236
|
async launch() {
|
|
238
237
|
if (await profileLooksLocked(QWEN_USER_DATA_DIR)) {
|
|
239
238
|
if (this.debug)
|
|
@@ -487,7 +486,6 @@ export class QwenBrowser {
|
|
|
487
486
|
}
|
|
488
487
|
catch { }
|
|
489
488
|
}
|
|
490
|
-
// ---------- login ----------
|
|
491
489
|
// Are we signed in? Detected from the PAGE, the same way a human sees it: a
|
|
492
490
|
// signed-out visitor has the header "Log in" / "Sign up" buttons, a signed-in
|
|
493
491
|
// one shows the account menu instead. The `auths/refresh` API was the first
|
|
@@ -1005,7 +1003,6 @@ export class QwenBrowser {
|
|
|
1005
1003
|
}
|
|
1006
1004
|
return false;
|
|
1007
1005
|
}
|
|
1008
|
-
// ---------- chat management ----------
|
|
1009
1006
|
async newChat() {
|
|
1010
1007
|
const before = await this.getCurrentChatId();
|
|
1011
1008
|
const btn = this.page.locator(NEW_CHAT_SELECTOR).first();
|
|
@@ -1272,7 +1269,6 @@ export class QwenBrowser {
|
|
|
1272
1269
|
getLastTokenUsage() {
|
|
1273
1270
|
return this._lastTokenUsage;
|
|
1274
1271
|
}
|
|
1275
|
-
// ---------- answer reading ----------
|
|
1276
1272
|
async _readLastAnswerText() {
|
|
1277
1273
|
if (this._netCapture && this._netCaptureAt >= this._lastSentAt) {
|
|
1278
1274
|
return this._netCapture;
|
|
@@ -1346,7 +1342,6 @@ export class QwenBrowser {
|
|
|
1346
1342
|
catch { }
|
|
1347
1343
|
return false;
|
|
1348
1344
|
}
|
|
1349
|
-
// ---------- toggles (model thinking / search) ----------
|
|
1350
1345
|
getToggleStatesSync() {
|
|
1351
1346
|
return this._toggles;
|
|
1352
1347
|
}
|
|
@@ -1523,7 +1518,6 @@ export class QwenBrowser {
|
|
|
1523
1518
|
}
|
|
1524
1519
|
catch { }
|
|
1525
1520
|
}
|
|
1526
|
-
// ---------- diagnostics ----------
|
|
1527
1521
|
async dumpDom(filePath) {
|
|
1528
1522
|
if (!this.page)
|
|
1529
1523
|
throw new Error('qwen: browser not launched');
|
|
@@ -1566,7 +1560,6 @@ export class QwenBrowser {
|
|
|
1566
1560
|
chatUrl(id) {
|
|
1567
1561
|
return chatUrl(id);
|
|
1568
1562
|
}
|
|
1569
|
-
// ---------- ask ----------
|
|
1570
1563
|
async _waitForSendSlot(agent) {
|
|
1571
1564
|
if (!agent)
|
|
1572
1565
|
return;
|
package/dist/qwen-chats.js
CHANGED
|
@@ -84,7 +84,6 @@ export function scrapeQwenChatMessages(opts) {
|
|
|
84
84
|
}
|
|
85
85
|
return out;
|
|
86
86
|
}
|
|
87
|
-
// ---------- API payload parsers (pure, unit-tested) ----------
|
|
88
87
|
/**
|
|
89
88
|
* Parse the chat list from `GET /api/v2/chats/?page=1&exclude_project=true`.
|
|
90
89
|
* The shape has drifted between builds, so accept several:
|
package/dist/qwen-net-capture.js
CHANGED
|
@@ -223,13 +223,10 @@ export function isFinishedWithoutAnswer(body) {
|
|
|
223
223
|
return extractFromSse(b) === '';
|
|
224
224
|
}
|
|
225
225
|
// True when the body carries Qwen's rate-limit / busy notice, so ask() can
|
|
226
|
-
// back off instead of waiting out the deadline.
|
|
227
|
-
//
|
|
228
|
-
//
|
|
229
|
-
//
|
|
230
|
-
// ERROR payload (`event: error` / `"type":"error"`) or as a code; answer text
|
|
231
|
-
// lives in `choices[].delta.content`. We therefore only inspect the body when
|
|
232
|
-
// it is NOT a plain answer stream, or when it carries no answer content.
|
|
226
|
+
// back off instead of waiting out the deadline. The classifier runs against the
|
|
227
|
+
// RAW body, where a phrase like `please try again later` also matches a NORMAL
|
|
228
|
+
// answer (the model writing about retry logic) and made ask() back off on a
|
|
229
|
+
// good turn. So it only counts an ERROR payload or a body with NO answer text.
|
|
233
230
|
export function isRateLimitText(body) {
|
|
234
231
|
const b = String(body || '');
|
|
235
232
|
if (!b)
|
package/dist/qwen-ui.js
CHANGED
|
@@ -174,9 +174,6 @@ export const STATUS_RE = /^(thinking|searching|generating|thinking completed|о
|
|
|
174
174
|
// Qwen's rate-limit / busy notices (best-effort; the toast may be short-lived).
|
|
175
175
|
export const RATE_LIMIT_RE = /too many requests|rate limit|too frequent|please try again later|слишком часто/i;
|
|
176
176
|
export const SERVER_BUSY_RE = /server is busy|service unavailable|try again later/i;
|
|
177
|
-
// ---------- toggles ----------
|
|
178
|
-
// The "Auto" thinking/search toggle and the mode selector. Read-only probing
|
|
179
|
-
// support; the model's thinking mode is set via config when supported.
|
|
180
177
|
// ---------- toggles (thinking mode / web search) ----------
|
|
181
178
|
// Qwen exposes thinking as a MODE dropdown (`.qwen-thinking-selector`, label
|
|
182
179
|
// "Auto" by default) with options Auto / Thinking / Fast — NOT a boolean
|
package/dist/run-task.js
CHANGED
|
@@ -330,7 +330,7 @@ export async function runTask(deps, browser, tools, taskText, workdir, opts, att
|
|
|
330
330
|
});
|
|
331
331
|
try {
|
|
332
332
|
// Set when the loop ends without a real answer (iteration limit / watchdog)
|
|
333
|
-
// so the one-shot mode can exit non-zero.
|
|
333
|
+
// so the one-shot mode can exit non-zero.
|
|
334
334
|
let failure = null;
|
|
335
335
|
// The machine-readable reason for the last task's outcome.
|
|
336
336
|
let outcomeKind = 'ok';
|
|
@@ -351,7 +351,7 @@ export async function runTask(deps, browser, tools, taskText, workdir, opts, att
|
|
|
351
351
|
// Calling it here made the spinner run for the whole pre-send phase (chat
|
|
352
352
|
// creation, throttle wait) with no generation in flight.
|
|
353
353
|
while (true) {
|
|
354
|
-
//
|
|
354
|
+
// Per-task summary: duration, number of tool calls and tokens spent.
|
|
355
355
|
const taskStart = Date.now();
|
|
356
356
|
// Token delta for THIS task: accumulated_token_usage is cumulative for
|
|
357
357
|
// the whole chat, so the per-task spend is after - before. Null when the
|
|
@@ -461,8 +461,8 @@ export async function runTask(deps, browser, tools, taskText, workdir, opts, att
|
|
|
461
461
|
else {
|
|
462
462
|
outcomeKind = 'ok';
|
|
463
463
|
}
|
|
464
|
-
//
|
|
465
|
-
//
|
|
464
|
+
// One summary line per task, printed even on an abort, so the operator
|
|
465
|
+
// sees what happened.
|
|
466
466
|
const tokensAfter = getTokenUsage ? getTokenUsage() : null;
|
|
467
467
|
const tokenDelta = typeof tokensBefore === 'number' && typeof tokensAfter === 'number'
|
|
468
468
|
? Math.max(0, tokensAfter - tokensBefore)
|
package/dist/self-review.js
CHANGED
|
@@ -122,7 +122,6 @@ async function copyContextFiles(srcDir, snapDir) {
|
|
|
122
122
|
}
|
|
123
123
|
}
|
|
124
124
|
}
|
|
125
|
-
// ---------- /self-review ----------
|
|
126
125
|
export async function selfReview({ browser, focus, transcript, locale, }) {
|
|
127
126
|
const t = translator(locale);
|
|
128
127
|
const stamp = new Date().toISOString().replace(/[:.]/g, '-');
|
|
@@ -190,7 +189,6 @@ export async function selfReview({ browser, focus, transcript, locale, }) {
|
|
|
190
189
|
console.log();
|
|
191
190
|
return { snapDir, reportPath, changed };
|
|
192
191
|
}
|
|
193
|
-
// ---------- /self-diff ----------
|
|
194
192
|
export async function selfDiff({ name, locale, }) {
|
|
195
193
|
const t = translator(locale);
|
|
196
194
|
const snapDir = path.join(SNAP_ROOT, name);
|
|
@@ -218,7 +216,6 @@ export async function selfDiff({ name, locale, }) {
|
|
|
218
216
|
console.log(theme.system(t('self.no_diff')));
|
|
219
217
|
}
|
|
220
218
|
}
|
|
221
|
-
// ---------- /self-apply ----------
|
|
222
219
|
export async function selfApply({ name, locale, }) {
|
|
223
220
|
const t = translator(locale);
|
|
224
221
|
const snapDir = path.join(SNAP_ROOT, name);
|
|
@@ -247,7 +244,6 @@ export async function selfApply({ name, locale, }) {
|
|
|
247
244
|
console.log(theme.system(t('self.backup', { dir: backupDir })));
|
|
248
245
|
console.log(theme.warn('\n' + t('self.restart_hint') + '\n'));
|
|
249
246
|
}
|
|
250
|
-
// ---------- /self-list ----------
|
|
251
247
|
export async function selfList({ locale, } = {}) {
|
|
252
248
|
const t = translator(locale);
|
|
253
249
|
const snapRoot = path.join(SNAP_ROOT);
|
|
@@ -285,7 +281,6 @@ export async function selfList({ locale, } = {}) {
|
|
|
285
281
|
console.log();
|
|
286
282
|
console.log(theme.system(t('self.list_commands') + '\n'));
|
|
287
283
|
}
|
|
288
|
-
// ---------- helpers ----------
|
|
289
284
|
async function diffFiles(origDir, newDir) {
|
|
290
285
|
const files = await listTsFiles(newDir).catch(() => []);
|
|
291
286
|
const changed = [];
|
package/dist/send-runtime.js
CHANGED
|
@@ -78,11 +78,9 @@ export class SendRuntime {
|
|
|
78
78
|
if (typeof extra.retryAfterMs === 'number') {
|
|
79
79
|
e.retryAfterMs = extra.retryAfterMs;
|
|
80
80
|
}
|
|
81
|
-
// A SUCCESS after a rate limit IS the lift of that block
|
|
82
|
-
//
|
|
83
|
-
//
|
|
84
|
-
// fold below clears `blockedAt` first. The measured duration is therefore
|
|
85
|
-
// taken HERE, before the state is folded; it is attached to the SAME event
|
|
81
|
+
// A SUCCESS after a rate limit IS the lift of that block: the retry happens
|
|
82
|
+
// IN PLACE and simply succeeds. The duration is therefore measured HERE,
|
|
83
|
+
// before the fold below clears `blockedAt`, and attached to the SAME event
|
|
86
84
|
// line, so one block still yields exactly one sample.
|
|
87
85
|
let blockMs;
|
|
88
86
|
if (outcome === 'ok' &&
|
|
@@ -101,11 +99,9 @@ export class SendRuntime {
|
|
|
101
99
|
this.state = { ...this.state, blocked: true, blockedAt: this.now() };
|
|
102
100
|
}
|
|
103
101
|
if (outcome === 'rate_limit') {
|
|
104
|
-
// The
|
|
105
|
-
//
|
|
106
|
-
//
|
|
107
|
-
// lower bound that would then be averaged together with the real
|
|
108
|
-
// duration written by onBlockLifted — the same block counted TWICE.
|
|
102
|
+
// The event carries NO duration: a rate-limit send is not the END of the
|
|
103
|
+
// block, so a value measured here would be averaged together with the
|
|
104
|
+
// real duration measured at the lift — the same block counted TWICE.
|
|
109
105
|
if (!this.state.blockedAt) {
|
|
110
106
|
this.state = { ...this.state, blocked: true, blockedAt: this.now() };
|
|
111
107
|
}
|
package/dist/send-telemetry.js
CHANGED
|
@@ -51,14 +51,12 @@ export function summarizeSends(events, now = Date.now()) {
|
|
|
51
51
|
const age = now - t;
|
|
52
52
|
return age >= 0 && age <= ms;
|
|
53
53
|
}).length;
|
|
54
|
-
// `blockMs` may arrive as a NUMBER (the writer) or a string (an older
|
|
55
|
-
// build, a hand-edited file): a numeric string is accepted so the average
|
|
56
|
-
// is not silently 0 for a file that records the block.
|
|
57
54
|
const blocks = events
|
|
58
|
-
// `
|
|
59
|
-
//
|
|
60
|
-
//
|
|
61
|
-
// block
|
|
55
|
+
// `blockMs` may arrive as a NUMBER (the writer) or a string (an older
|
|
56
|
+
// build, a hand-edited file), so it is coerced. A missing value must NOT
|
|
57
|
+
// become 0: 0 is a finite non-negative number, and an event without a
|
|
58
|
+
// block duration (the rate-limit event only records `blockedAt`) was
|
|
59
|
+
// averaged as a ZERO-length block, halving the reported average.
|
|
62
60
|
.map((e) => e.blockMs === null || e.blockMs === undefined ? NaN : Number(e.blockMs))
|
|
63
61
|
// A finite value is not enough: the SUM of many large durations overflows
|
|
64
62
|
// a JS number (two `Number.MAX_VALUE` entries add up to Infinity), so the
|
package/dist/send-throttle.js
CHANGED
|
@@ -39,11 +39,10 @@ function prune(recent, now, windowMs) {
|
|
|
39
39
|
*/
|
|
40
40
|
export function nextWaitMs(state, lastSentAt, now) {
|
|
41
41
|
if (state.forcedWaitMs > 0) {
|
|
42
|
-
// A forced wait must EXPIRE:
|
|
43
|
-
//
|
|
44
|
-
//
|
|
45
|
-
//
|
|
46
|
-
// the current call, and expires on the next.
|
|
42
|
+
// A forced wait must EXPIRE: with only `forcedWaitMs > 0` a long
|
|
43
|
+
// Retry-After blocked every send until another event cleared it. The
|
|
44
|
+
// request stamp makes the remaining time exact; without one (a caller-built
|
|
45
|
+
// or restored state) the wait is reported ONCE, from the current call.
|
|
47
46
|
if (state.forcedWaitAt) {
|
|
48
47
|
const left = state.forcedWaitMs - (now - state.forcedWaitAt);
|
|
49
48
|
return left > 0 ? left : 0;
|
package/dist/sessions.js
CHANGED
|
@@ -133,13 +133,12 @@ function writeIndex({ id, workdir }) {
|
|
|
133
133
|
}
|
|
134
134
|
catch { }
|
|
135
135
|
}
|
|
136
|
-
// The last session for the working directory
|
|
137
|
-
//
|
|
138
|
-
//
|
|
139
|
-
//
|
|
140
|
-
//
|
|
141
|
-
//
|
|
142
|
-
// global last only within the same provider).
|
|
136
|
+
// The last session for the working directory (the last one overall when the
|
|
137
|
+
// directory has none — useful when launched from a new place), restricted to
|
|
138
|
+
// `provider` when given. A chat id only exists on ITS backend, so restoring a
|
|
139
|
+
// DeepSeek chat while the active provider is Qwen (or vice versa) would fail to
|
|
140
|
+
// open; the filter makes auto-restore and /last pick the right one, and fall
|
|
141
|
+
// back to the global last only within the same provider.
|
|
143
142
|
export function loadLastSession(workdir = '', provider) {
|
|
144
143
|
try {
|
|
145
144
|
const index = JSON.parse(fs.readFileSync(INDEX_FILE, 'utf-8'));
|
package/dist/spinner.js
CHANGED
|
@@ -152,10 +152,9 @@ export function createSpinner(locale = 'ru') {
|
|
|
152
152
|
}
|
|
153
153
|
startThinking();
|
|
154
154
|
},
|
|
155
|
-
// The agent is waiting out the send-interval pause before a real send
|
|
156
|
-
//
|
|
157
|
-
//
|
|
158
|
-
// was printed and the dots stayed frozen).
|
|
155
|
+
// The agent is waiting out the send-interval pause before a real send: an
|
|
156
|
+
// ANIMATED status with the remaining seconds, so the spinner keeps moving
|
|
157
|
+
// (a static line made the pause look frozen).
|
|
159
158
|
sendPause: (seconds) => {
|
|
160
159
|
if (pending)
|
|
161
160
|
return;
|
package/dist/statusline.js
CHANGED
|
@@ -58,10 +58,6 @@ export function runStatusLineCommand(workdir, command, info, timeoutMs = 4000) {
|
|
|
58
58
|
// (the row overflows and the cursor arithmetic drifts).
|
|
59
59
|
resolve(clipBadge(first));
|
|
60
60
|
};
|
|
61
|
-
// Only the FIRST LINE is shown, so there is no reason to keep collecting a
|
|
62
|
-
// big blob: a chatty command (a JSON dump, `ls -R`) would grow `out`
|
|
63
|
-
// unboundedly and the status row then repainted megabytes. Stop appending
|
|
64
|
-
// once a short line is buffered (the rest of that line does not matter).
|
|
65
61
|
const timer = setTimeout(() => {
|
|
66
62
|
try {
|
|
67
63
|
if (process.platform !== 'win32' && child.pid) {
|
|
@@ -74,15 +70,15 @@ export function runStatusLineCommand(workdir, command, info, timeoutMs = 4000) {
|
|
|
74
70
|
catch { }
|
|
75
71
|
finish();
|
|
76
72
|
}, timeoutMs);
|
|
77
|
-
//
|
|
78
|
-
//
|
|
73
|
+
// Only the FIRST line is shown and the status line is a short badge, so the
|
|
74
|
+
// buffer is capped: a chatty command (a JSON dump, `ls -R`) would otherwise
|
|
75
|
+
// grow `out` and make the status row repaint megabytes on every tick.
|
|
79
76
|
const MAX_OUT = 400;
|
|
80
77
|
child.stdout?.on('data', (c) => {
|
|
81
78
|
if (out.length >= MAX_OUT)
|
|
82
79
|
return;
|
|
83
|
-
// A chunk can be huge (one 64 KB read)
|
|
84
|
-
//
|
|
85
|
-
// status row repaint megabytes on every tick.
|
|
80
|
+
// A chunk can be huge (one 64 KB read): clip it to the remaining space so
|
|
81
|
+
// the buffer never exceeds MAX_OUT.
|
|
86
82
|
out += c.toString().slice(0, MAX_OUT - out.length);
|
|
87
83
|
});
|
|
88
84
|
child.on('error', () => {
|
package/dist/system-prompt.js
CHANGED
|
@@ -124,7 +124,7 @@ export function renderContextSection(context) {
|
|
|
124
124
|
f.content +
|
|
125
125
|
'\n';
|
|
126
126
|
}
|
|
127
|
-
//
|
|
127
|
+
// Nested AGENTS.md/MEMORY.md from the directories this task touches.
|
|
128
128
|
// Deliberately a SEPARATE section: these apply only to part of the tree and
|
|
129
129
|
// must not be mistaken for project-wide rules.
|
|
130
130
|
for (const f of context.scopedAgents || []) {
|
package/dist/tui/widgets.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "zames_pro",
|
|
3
|
-
"version": "2.82.
|
|
3
|
+
"version": "2.82.138",
|
|
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": {
|